The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/ncsw/etc/mm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright 2008-2012 Freescale Semiconductor Inc.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions are met:
    6  *     * Redistributions of source code must retain the above copyright
    7  *       notice, this list of conditions and the following disclaimer.
    8  *     * Redistributions in binary form must reproduce the above copyright
    9  *       notice, this list of conditions and the following disclaimer in the
   10  *       documentation and/or other materials provided with the distribution.
   11  *     * Neither the name of Freescale Semiconductor nor the
   12  *       names of its contributors may be used to endorse or promote products
   13  *       derived from this software without specific prior written permission.
   14  *
   15  *
   16  * ALTERNATIVELY, this software may be distributed under the terms of the
   17  * GNU General Public License ("GPL") as published by the Free Software
   18  * Foundation, either version 2 of that License or (at your option) any
   19  * later version.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
   22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   24  * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
   25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   28  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 
   34 #include "string_ext.h"
   35 #include "error_ext.h"
   36 #include "std_ext.h"
   37 #include "part_ext.h"
   38 #include "xx_ext.h"
   39 
   40 #include "mm.h"
   41 
   42 
   43 
   44 
   45 /**********************************************************************
   46  *                     MM internal routines set                       *
   47  **********************************************************************/
   48 
   49 /****************************************************************
   50  *  Routine:   CreateBusyBlock
   51  *
   52  *  Description:
   53  *      Initializes a new busy block of "size" bytes and started
   54  *      rom "base" address. Each busy block has a name that
   55  *      specified the purpose of the memory allocation.
   56  *
   57  *  Arguments:
   58  *      base      - base address of the busy block
   59  *      size      - size of the busy block
   60  *      name      - name that specified the busy block
   61  *
   62  *  Return value:
   63  *      A pointer to new created structure returned on success;
   64  *      Otherwise, NULL.
   65  ****************************************************************/
   66 static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name)
   67 {
   68     t_BusyBlock *p_BusyBlock;
   69     uint32_t    n;
   70 
   71     p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock));
   72     if ( !p_BusyBlock )
   73     {
   74         REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
   75         return NULL;
   76     }
   77 
   78     p_BusyBlock->base = base;
   79     p_BusyBlock->end = base + size;
   80 
   81     n = strlen(name);
   82     if (n >= MM_MAX_NAME_LEN)
   83         n = MM_MAX_NAME_LEN - 1;
   84     strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1);
   85     p_BusyBlock->name[n] = '\0';
   86     p_BusyBlock->p_Next = 0;
   87 
   88     return p_BusyBlock;
   89 }
   90 
   91 /****************************************************************
   92  *  Routine:   CreateNewBlock
   93  *
   94  *  Description:
   95  *      Initializes a new memory block of "size" bytes and started
   96  *      from "base" address.
   97  *
   98  *  Arguments:
   99  *      base    - base address of the memory block
  100  *      size    - size of the memory block
  101  *
  102  *  Return value:
  103  *      A pointer to new created structure returned on success;
  104  *      Otherwise, NULL.
  105  ****************************************************************/
  106 static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size)
  107 {
  108     t_MemBlock *p_MemBlock;
  109 
  110     p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock));
  111     if ( !p_MemBlock )
  112     {
  113         REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  114         return NULL;
  115     }
  116 
  117     p_MemBlock->base = base;
  118     p_MemBlock->end = base+size;
  119     p_MemBlock->p_Next = 0;
  120 
  121     return p_MemBlock;
  122 }
  123 
  124 /****************************************************************
  125  *  Routine:   CreateFreeBlock
  126  *
  127  *  Description:
  128  *      Initializes a new free block of of "size" bytes and
  129  *      started from "base" address.
  130  *
  131  *  Arguments:
  132  *      base      - base address of the free block
  133  *      size      - size of the free block
  134  *
  135  *  Return value:
  136  *      A pointer to new created structure returned on success;
  137  *      Otherwise, NULL.
  138  ****************************************************************/
  139 static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size)
  140 {
  141     t_FreeBlock *p_FreeBlock;
  142 
  143     p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock));
  144     if ( !p_FreeBlock )
  145     {
  146         REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  147         return NULL;
  148     }
  149 
  150     p_FreeBlock->base = base;
  151     p_FreeBlock->end = base + size;
  152     p_FreeBlock->p_Next = 0;
  153 
  154     return p_FreeBlock;
  155 }
  156 
  157 /****************************************************************
  158  *  Routine:    AddFree
  159  *
  160  *  Description:
  161  *      Adds a new free block to the free lists. It updates each
  162  *      free list to include a new free block.
  163  *      Note, that all free block in each free list are ordered
  164  *      by their base address.
  165  *
  166  *  Arguments:
  167  *      p_MM  - pointer to the MM object
  168  *      base  - base address of a given free block
  169  *      end   - end address of a given free block
  170  *
  171  *  Return value:
  172  *
  173  *
  174  ****************************************************************/
  175 static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end)
  176 {
  177     t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
  178     uint64_t    alignment;
  179     uint64_t    alignBase;
  180     int         i;
  181 
  182     /* Updates free lists to include  a just released block */
  183     for (i=0; i <= MM_MAX_ALIGNMENT; i++)
  184     {
  185         p_PrevB = p_NewB = 0;
  186         p_CurrB = p_MM->freeBlocks[i];
  187 
  188         alignment = (uint64_t)(0x1 << i);
  189         alignBase = MAKE_ALIGNED(base, alignment);
  190 
  191         /* Goes to the next free list if there is no block to free */
  192         if (alignBase >= end)
  193             continue;
  194 
  195         /* Looks for a free block that should be updated */
  196         while ( p_CurrB )
  197         {
  198             if ( alignBase <= p_CurrB->end )
  199             {
  200                 if ( end > p_CurrB->end )
  201                 {
  202                     t_FreeBlock *p_NextB;
  203                     while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end )
  204                     {
  205                         p_NextB = p_CurrB->p_Next;
  206                         p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
  207                         XX_Free(p_NextB);
  208                     }
  209 
  210                     p_NextB = p_CurrB->p_Next;
  211                     if ( !p_NextB || (p_NextB && end < p_NextB->base) )
  212                     {
  213                         p_CurrB->end = end;
  214                     }
  215                     else
  216                     {
  217                         p_CurrB->end = p_NextB->end;
  218                         p_CurrB->p_Next = p_NextB->p_Next;
  219                         XX_Free(p_NextB);
  220                     }
  221                 }
  222                 else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) )
  223                 {
  224                     if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
  225                         RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  226 
  227                     p_NewB->p_Next = p_CurrB;
  228                     if (p_PrevB)
  229                         p_PrevB->p_Next = p_NewB;
  230                     else
  231                         p_MM->freeBlocks[i] = p_NewB;
  232                     break;
  233                 }
  234 
  235                 if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base))
  236                 {
  237                     p_CurrB->base = alignBase;
  238                 }
  239 
  240                 /* if size of the free block is less then alignment
  241                  * deletes that free block from the free list. */
  242                 if ( (p_CurrB->end - p_CurrB->base) < alignment)
  243                 {
  244                     if ( p_PrevB )
  245                         p_PrevB->p_Next = p_CurrB->p_Next;
  246                     else
  247                         p_MM->freeBlocks[i] = p_CurrB->p_Next;
  248                     XX_Free(p_CurrB);
  249                     p_CurrB = NULL;
  250                 }
  251                 break;
  252             }
  253             else
  254             {
  255                 p_PrevB = p_CurrB;
  256                 p_CurrB = p_CurrB->p_Next;
  257             }
  258         }
  259 
  260         /* If no free block found to be updated, insert a new free block
  261          * to the end of the free list.
  262          */
  263         if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) )
  264         {
  265             if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL)
  266                 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  267 
  268             if (p_PrevB)
  269                 p_PrevB->p_Next = p_NewB;
  270             else
  271                 p_MM->freeBlocks[i] = p_NewB;
  272         }
  273 
  274         /* Update boundaries of the new free block */
  275         if ((alignment == 1) && !p_NewB)
  276         {
  277             if ( p_CurrB && base > p_CurrB->base )
  278                 base = p_CurrB->base;
  279             if ( p_CurrB && end < p_CurrB->end )
  280                 end = p_CurrB->end;
  281         }
  282     }
  283 
  284     return (E_OK);
  285 }
  286 
  287 /****************************************************************
  288  *  Routine:      CutFree
  289  *
  290  *  Description:
  291  *      Cuts a free block from holdBase to holdEnd from the free lists.
  292  *      That is, it updates all free lists of the MM object do
  293  *      not include a block of memory from holdBase to holdEnd.
  294  *      For each free lists it seek for a free block that holds
  295  *      either holdBase or holdEnd. If such block is found it updates it.
  296  *
  297  *  Arguments:
  298  *      p_MM            - pointer to the MM object
  299  *      holdBase        - base address of the allocated block
  300  *      holdEnd         - end address of the allocated block
  301  *
  302  *  Return value:
  303  *      E_OK is returned on success,
  304  *      otherwise returns an error code.
  305  *
  306  ****************************************************************/
  307 static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd)
  308 {
  309     t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
  310     uint64_t    alignBase, base, end;
  311     uint64_t    alignment;
  312     int         i;
  313 
  314     for (i=0; i <= MM_MAX_ALIGNMENT; i++)
  315     {
  316         p_PrevB = p_NewB = 0;
  317         p_CurrB = p_MM->freeBlocks[i];
  318 
  319         alignment = (uint64_t)(0x1 << i);
  320         alignBase = MAKE_ALIGNED(holdEnd, alignment);
  321 
  322         while ( p_CurrB )
  323         {
  324             base = p_CurrB->base;
  325             end = p_CurrB->end;
  326 
  327             if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) )
  328             {
  329                 if ( alignBase >= end ||
  330                      (alignBase < end && ((end-alignBase) < alignment)) )
  331                 {
  332                     if (p_PrevB)
  333                         p_PrevB->p_Next = p_CurrB->p_Next;
  334                     else
  335                         p_MM->freeBlocks[i] = p_CurrB->p_Next;
  336                     XX_Free(p_CurrB);
  337                 }
  338                 else
  339                 {
  340                     p_CurrB->base = alignBase;
  341                 }
  342                 break;
  343             }
  344             else if ( (holdBase > base) && (holdEnd <= end) )
  345             {
  346                 if ( (holdBase-base) >= alignment )
  347                 {
  348                     if ( (alignBase < end) && ((end-alignBase) >= alignment) )
  349                     {
  350                         if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
  351                             RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  352                         p_NewB->p_Next = p_CurrB->p_Next;
  353                         p_CurrB->p_Next = p_NewB;
  354                     }
  355                     p_CurrB->end = holdBase;
  356                 }
  357                 else if ( (alignBase < end) && ((end-alignBase) >= alignment) )
  358                 {
  359                     p_CurrB->base = alignBase;
  360                 }
  361                 else
  362                 {
  363                     if (p_PrevB)
  364                         p_PrevB->p_Next = p_CurrB->p_Next;
  365                     else
  366                         p_MM->freeBlocks[i] = p_CurrB->p_Next;
  367                     XX_Free(p_CurrB);
  368                 }
  369                 break;
  370             }
  371             else
  372             {
  373                 p_PrevB = p_CurrB;
  374                 p_CurrB = p_CurrB->p_Next;
  375             }
  376         }
  377     }
  378 
  379     return (E_OK);
  380 }
  381 
  382 /****************************************************************
  383  *  Routine:     AddBusy
  384  *
  385  *  Description:
  386  *      Adds a new busy block to the list of busy blocks. Note,
  387  *      that all busy blocks are ordered by their base address in
  388  *      the busy list.
  389  *
  390  *  Arguments:
  391  *      MM              - handler to the MM object
  392  *      p_NewBusyB      - pointer to the a busy block
  393  *
  394  *  Return value:
  395  *      None.
  396  *
  397  ****************************************************************/
  398 static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB)
  399 {
  400     t_BusyBlock *p_CurrBusyB, *p_PrevBusyB;
  401 
  402     /* finds a place of a new busy block in the list of busy blocks */
  403     p_PrevBusyB = 0;
  404     p_CurrBusyB = p_MM->busyBlocks;
  405 
  406     while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base )
  407     {
  408         p_PrevBusyB = p_CurrBusyB;
  409         p_CurrBusyB = p_CurrBusyB->p_Next;
  410     }
  411 
  412     /* insert the new busy block into the list of busy blocks */
  413     if ( p_CurrBusyB )
  414         p_NewBusyB->p_Next = p_CurrBusyB;
  415     if ( p_PrevBusyB )
  416         p_PrevBusyB->p_Next = p_NewBusyB;
  417     else
  418         p_MM->busyBlocks = p_NewBusyB;
  419 }
  420 
  421 /****************************************************************
  422  *  Routine:    CutBusy
  423  *
  424  *  Description:
  425  *      Cuts a block from base to end from the list of busy blocks.
  426  *      This is done by updating the list of busy blocks do not
  427  *      include a given block, that block is going to be free. If a
  428  *      given block is a part of some other busy block, so that
  429  *      busy block is updated. If there are number of busy blocks
  430  *      included in the given block, so all that blocks are removed
  431  *      from the busy list and the end blocks are updated.
  432  *      If the given block devides some block into two parts, a new
  433  *      busy block is added to the busy list.
  434  *
  435  *  Arguments:
  436  *      p_MM  - pointer to the MM object
  437  *      base  - base address of a given busy block
  438  *      end   - end address of a given busy block
  439  *
  440  *  Return value:
  441  *      E_OK on success, E_NOMEMORY otherwise.
  442  *
  443  ****************************************************************/
  444 static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end)
  445 {
  446     t_BusyBlock  *p_CurrB, *p_PrevB, *p_NewB;
  447 
  448     p_CurrB = p_MM->busyBlocks;
  449     p_PrevB = p_NewB = 0;
  450 
  451     while ( p_CurrB )
  452     {
  453         if ( base < p_CurrB->end )
  454         {
  455             if ( end > p_CurrB->end )
  456             {
  457                 t_BusyBlock *p_NextB;
  458                 while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end )
  459                 {
  460                     p_NextB = p_CurrB->p_Next;
  461                     p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
  462                     XX_Free(p_NextB);
  463                 }
  464 
  465                 p_NextB = p_CurrB->p_Next;
  466                 if ( p_NextB && end > p_NextB->base )
  467                 {
  468                     p_NextB->base = end;
  469                 }
  470             }
  471 
  472             if ( base <= p_CurrB->base )
  473             {
  474                 if ( end < p_CurrB->end && end > p_CurrB->base )
  475                 {
  476                     p_CurrB->base = end;
  477                 }
  478                 else if ( end >= p_CurrB->end )
  479                 {
  480                     if ( p_PrevB )
  481                         p_PrevB->p_Next = p_CurrB->p_Next;
  482                     else
  483                         p_MM->busyBlocks = p_CurrB->p_Next;
  484                     XX_Free(p_CurrB);
  485                 }
  486             }
  487             else
  488             {
  489                 if ( end < p_CurrB->end && end > p_CurrB->base )
  490                 {
  491                     if ((p_NewB = CreateBusyBlock(end,
  492                                                   p_CurrB->end-end,
  493                                                   p_CurrB->name)) == NULL)
  494                         RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  495                     p_NewB->p_Next = p_CurrB->p_Next;
  496                     p_CurrB->p_Next = p_NewB;
  497                 }
  498                 p_CurrB->end = base;
  499             }
  500             break;
  501         }
  502         else
  503         {
  504             p_PrevB = p_CurrB;
  505             p_CurrB = p_CurrB->p_Next;
  506         }
  507     }
  508 
  509     return (E_OK);
  510 }
  511 
  512 /****************************************************************
  513  *  Routine:     MmGetGreaterAlignment
  514  *
  515  *  Description:
  516  *      Allocates a block of memory according to the given size
  517  *      and the alignment. That routine is called from the MM_Get
  518  *      routine if the required alignment is greater then MM_MAX_ALIGNMENT.
  519  *      In that case, it goes over free blocks of 64 byte align list
  520  *      and checks if it has the required size of bytes of the required
  521  *      alignment. If no blocks found returns ILLEGAL_BASE.
  522  *      After the block is found and data is allocated, it calls
  523  *      the internal CutFree routine to update all free lists
  524  *      do not include a just allocated block. Of course, each
  525  *      free list contains a free blocks with the same alignment.
  526  *      It is also creates a busy block that holds
  527  *      information about an allocated block.
  528  *
  529  *  Arguments:
  530  *      MM              - handle to the MM object
  531  *      size            - size of the MM
  532  *      alignment       - index as a power of two defines
  533  *                        a required alignment that is greater then 64.
  534  *      name            - the name that specifies an allocated block.
  535  *
  536  *  Return value:
  537  *      base address of an allocated block.
  538  *      ILLEGAL_BASE if can't allocate a block
  539  *
  540  ****************************************************************/
  541 static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name)
  542 {
  543     t_FreeBlock *p_FreeB;
  544     t_BusyBlock *p_NewBusyB;
  545     uint64_t    holdBase, holdEnd, alignBase = 0;
  546 
  547     /* goes over free blocks of the 64 byte alignment list
  548        and look for a block of the suitable size and
  549        base address according to the alignment. */
  550     p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT];
  551 
  552     while ( p_FreeB )
  553     {
  554         alignBase = MAKE_ALIGNED(p_FreeB->base, alignment);
  555 
  556         /* the block is found if the aligned base inside the block
  557          * and has the anough size. */
  558         if ( alignBase >= p_FreeB->base &&
  559              alignBase < p_FreeB->end &&
  560              size <= (p_FreeB->end - alignBase) )
  561             break;
  562         else
  563             p_FreeB = p_FreeB->p_Next;
  564     }
  565 
  566     /* If such block isn't found */
  567     if ( !p_FreeB )
  568         return (uint64_t)(ILLEGAL_BASE);
  569 
  570     holdBase = alignBase;
  571     holdEnd = alignBase + size;
  572 
  573     /* init a new busy block */
  574     if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
  575         return (uint64_t)(ILLEGAL_BASE);
  576 
  577     /* calls Update routine to update a lists of free blocks */
  578     if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
  579     {
  580         XX_Free(p_NewBusyB);
  581         return (uint64_t)(ILLEGAL_BASE);
  582     }
  583 
  584     /* insert the new busy block into the list of busy blocks */
  585     AddBusy ( p_MM, p_NewBusyB );
  586 
  587     return (holdBase);
  588 }
  589 
  590 
  591 /**********************************************************************
  592  *                     MM API routines set                            *
  593  **********************************************************************/
  594 
  595 /*****************************************************************************/
  596 t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size)
  597 {
  598     t_MM        *p_MM;
  599     uint64_t    newBase, newSize;
  600     int         i;
  601 
  602     if (!size)
  603     {
  604         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)"));
  605     }
  606 
  607     /* Initializes a new MM object */
  608     p_MM = (t_MM *)XX_Malloc(sizeof(t_MM));
  609     if (!p_MM)
  610     {
  611         RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  612     }
  613 
  614     p_MM->h_Spinlock = XX_InitSpinlock();
  615     if (!p_MM->h_Spinlock)
  616     {
  617         XX_Free(p_MM);
  618         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!"));
  619     }
  620 
  621     /* Initializes counter of free memory to total size */
  622     p_MM->freeMemSize = size;
  623 
  624     /* A busy list is empty */
  625     p_MM->busyBlocks = 0;
  626 
  627     /* Initializes a new memory block */
  628     if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL)
  629     {
  630         MM_Free(p_MM);
  631         RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  632     }
  633 
  634     /* Initializes a new free block for each free list*/
  635     for (i=0; i <= MM_MAX_ALIGNMENT; i++)
  636     {
  637         newBase = MAKE_ALIGNED( base, (0x1 << i) );
  638         newSize = size - (newBase - base);
  639 
  640         if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL)
  641         {
  642             MM_Free(p_MM);
  643             RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
  644         }
  645     }
  646 
  647     *h_MM = p_MM;
  648 
  649     return (E_OK);
  650 }
  651 
  652 /*****************************************************************************/
  653 void MM_Free(t_Handle h_MM)
  654 {
  655     t_MM        *p_MM = (t_MM *)h_MM;
  656     t_MemBlock  *p_MemBlock;
  657     t_BusyBlock *p_BusyBlock;
  658     t_FreeBlock *p_FreeBlock;
  659     void        *p_Block;
  660     int         i;
  661 
  662     ASSERT_COND(p_MM);
  663 
  664     /* release memory allocated for busy blocks */
  665     p_BusyBlock = p_MM->busyBlocks;
  666     while ( p_BusyBlock )
  667     {
  668         p_Block = p_BusyBlock;
  669         p_BusyBlock = p_BusyBlock->p_Next;
  670         XX_Free(p_Block);
  671     }
  672 
  673     /* release memory allocated for free blocks */
  674     for (i=0; i <= MM_MAX_ALIGNMENT; i++)
  675     {
  676         p_FreeBlock = p_MM->freeBlocks[i];
  677         while ( p_FreeBlock )
  678         {
  679             p_Block = p_FreeBlock;
  680             p_FreeBlock = p_FreeBlock->p_Next;
  681             XX_Free(p_Block);
  682         }
  683     }
  684 
  685     /* release memory allocated for memory blocks */
  686     p_MemBlock = p_MM->memBlocks;
  687     while ( p_MemBlock )
  688     {
  689         p_Block = p_MemBlock;
  690         p_MemBlock = p_MemBlock->p_Next;
  691         XX_Free(p_Block);
  692     }
  693 
  694     if (p_MM->h_Spinlock)
  695         XX_FreeSpinlock(p_MM->h_Spinlock);
  696 
  697     /* release memory allocated for MM object itself */
  698     XX_Free(p_MM);
  699 }
  700 
  701 /*****************************************************************************/
  702 uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name)
  703 {
  704     t_MM        *p_MM = (t_MM *)h_MM;
  705     t_FreeBlock *p_FreeB;
  706     t_BusyBlock *p_NewBusyB;
  707     uint64_t    holdBase, holdEnd, j, i = 0;
  708     uint32_t    intFlags;
  709 
  710     SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE);
  711 
  712     /* checks that alignment value is greater then zero */
  713     if (alignment == 0)
  714     {
  715         alignment = 1;
  716     }
  717 
  718     j = alignment;
  719 
  720     /* checks if alignment is a power of two, if it correct and if the
  721        required size is multiple of the given alignment. */
  722     while ((j & 0x1) == 0)
  723     {
  724         i++;
  725         j = j >> 1;
  726     }
  727 
  728     /* if the given alignment isn't power of two, returns an error */
  729     if (j != 1)
  730     {
  731         REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)"));
  732         return (uint64_t)ILLEGAL_BASE;
  733     }
  734 
  735     if (i > MM_MAX_ALIGNMENT)
  736     {
  737         return (MmGetGreaterAlignment(p_MM, size, alignment, name));
  738     }
  739 
  740     intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
  741     /* look for a block of the size greater or equal to the required size. */
  742     p_FreeB = p_MM->freeBlocks[i];
  743     while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size )
  744         p_FreeB = p_FreeB->p_Next;
  745 
  746     /* If such block is found */
  747     if ( !p_FreeB )
  748     {
  749         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  750         return (uint64_t)(ILLEGAL_BASE);
  751     }
  752 
  753     holdBase = p_FreeB->base;
  754     holdEnd = holdBase + size;
  755 
  756     /* init a new busy block */
  757     if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
  758     {
  759         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  760         return (uint64_t)(ILLEGAL_BASE);
  761     }
  762 
  763     /* calls Update routine to update a lists of free blocks */
  764     if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
  765     {
  766         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  767         XX_Free(p_NewBusyB);
  768         return (uint64_t)(ILLEGAL_BASE);
  769     }
  770 
  771     /* Decreasing the allocated memory size from free memory size */
  772     p_MM->freeMemSize -= size;
  773 
  774     /* insert the new busy block into the list of busy blocks */
  775     AddBusy ( p_MM, p_NewBusyB );
  776     XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  777 
  778     return (holdBase);
  779 }
  780 
  781 /*****************************************************************************/
  782 uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name)
  783 {
  784     t_MM        *p_MM = (t_MM *)h_MM;
  785     t_FreeBlock *p_FreeB;
  786     t_BusyBlock *p_NewBusyB;
  787     uint32_t    intFlags;
  788     bool        blockIsFree = FALSE;
  789 
  790     ASSERT_COND(p_MM);
  791 
  792     intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
  793     p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the
  794                                       free list with alignment 1 */
  795 
  796     while ( p_FreeB )
  797     {
  798         if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end )
  799         {
  800             blockIsFree = TRUE;
  801             break;
  802         }
  803         else
  804             p_FreeB = p_FreeB->p_Next;
  805     }
  806 
  807     if ( !blockIsFree )
  808     {
  809         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  810         return (uint64_t)(ILLEGAL_BASE);
  811     }
  812 
  813     /* init a new busy block */
  814     if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL)
  815     {
  816         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  817         return (uint64_t)(ILLEGAL_BASE);
  818     }
  819 
  820     /* calls Update routine to update a lists of free blocks */
  821     if ( CutFree ( p_MM, base, base+size ) != E_OK )
  822     {
  823         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  824         XX_Free(p_NewBusyB);
  825         return (uint64_t)(ILLEGAL_BASE);
  826     }
  827 
  828     /* Decreasing the allocated memory size from free memory size */
  829     p_MM->freeMemSize -= size;
  830 
  831     /* insert the new busy block into the list of busy blocks */
  832     AddBusy ( p_MM, p_NewBusyB );
  833     XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  834 
  835     return (base);
  836 }
  837 
  838 /*****************************************************************************/
  839 uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name)
  840 {
  841     t_MM        *p_MM = (t_MM *)h_MM;
  842     t_FreeBlock *p_FreeB;
  843     t_BusyBlock *p_NewBusyB;
  844     uint64_t    holdBase, holdEnd, j = alignment, i=0;
  845     uint32_t    intFlags;
  846 
  847     ASSERT_COND(p_MM);
  848 
  849     /* checks if alignment is a power of two, if it correct and if the
  850        required size is multiple of the given alignment. */
  851     while ((j & 0x1) == 0)
  852     {
  853         i++;
  854         j = j >> 1;
  855     }
  856 
  857     if ( (j != 1) || (i > MM_MAX_ALIGNMENT) )
  858     {
  859         return (uint64_t)(ILLEGAL_BASE);
  860     }
  861 
  862     intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
  863     p_FreeB = p_MM->freeBlocks[i];
  864 
  865     /* look for the first block that contains the minimum
  866        base address. If the whole required size may be fit
  867        into it, use that block, otherwise look for the next
  868        block of size greater or equal to the required size. */
  869     while ( p_FreeB && (min >= p_FreeB->end))
  870             p_FreeB = p_FreeB->p_Next;
  871 
  872     /* If such block is found */
  873     if ( !p_FreeB )
  874     {
  875         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  876         return (uint64_t)(ILLEGAL_BASE);
  877     }
  878 
  879     /* if this block is large enough, use this block */
  880     holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min;
  881     if ((holdBase + size) <= p_FreeB->end )
  882     {
  883         holdEnd = holdBase + size;
  884     }
  885     else
  886     {
  887         p_FreeB = p_FreeB->p_Next;
  888         while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) )
  889             p_FreeB = p_FreeB->p_Next;
  890 
  891         /* If such block is found */
  892         if ( !p_FreeB )
  893         {
  894             XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  895             return (uint64_t)(ILLEGAL_BASE);
  896         }
  897 
  898         holdBase = p_FreeB->base;
  899         holdEnd = holdBase + size;
  900     }
  901 
  902     /* init a new busy block */
  903     if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
  904     {
  905         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  906         return (uint64_t)(ILLEGAL_BASE);
  907     }
  908 
  909     /* calls Update routine to update a lists of free blocks */
  910     if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK )
  911     {
  912         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  913         XX_Free(p_NewBusyB);
  914         return (uint64_t)(ILLEGAL_BASE);
  915     }
  916 
  917     /* Decreasing the allocated memory size from free memory size */
  918     p_MM->freeMemSize -= size;
  919 
  920     /* insert the new busy block into the list of busy blocks */
  921     AddBusy( p_MM, p_NewBusyB );
  922     XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  923 
  924     return (holdBase);
  925 }
  926 
  927 /*****************************************************************************/
  928 uint64_t MM_Put(t_Handle h_MM, uint64_t base)
  929 {
  930     t_MM        *p_MM = (t_MM *)h_MM;
  931     t_BusyBlock *p_BusyB, *p_PrevBusyB;
  932     uint64_t    size;
  933     uint32_t    intFlags;
  934 
  935     ASSERT_COND(p_MM);
  936 
  937     /* Look for a busy block that have the given base value.
  938      * That block will be returned back to the memory.
  939      */
  940     p_PrevBusyB = 0;
  941 
  942     intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
  943     p_BusyB = p_MM->busyBlocks;
  944     while ( p_BusyB && base != p_BusyB->base )
  945     {
  946         p_PrevBusyB = p_BusyB;
  947         p_BusyB = p_BusyB->p_Next;
  948     }
  949 
  950     if ( !p_BusyB )
  951     {
  952         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  953         return (uint64_t)(0);
  954     }
  955 
  956     if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK )
  957     {
  958         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  959         return (uint64_t)(0);
  960     }
  961 
  962     /* removes a busy block form the list of busy blocks */
  963     if ( p_PrevBusyB )
  964         p_PrevBusyB->p_Next = p_BusyB->p_Next;
  965     else
  966         p_MM->busyBlocks = p_BusyB->p_Next;
  967 
  968     size = p_BusyB->end - p_BusyB->base;
  969 
  970     /* Adding the deallocated memory size to free memory size */
  971     p_MM->freeMemSize += size;
  972 
  973     XX_Free(p_BusyB);
  974     XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  975 
  976     return (size);
  977 }
  978 
  979 /*****************************************************************************/
  980 uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size)
  981 {
  982     t_MM        *p_MM = (t_MM *)h_MM;
  983     uint64_t    end = base + size;
  984     uint32_t    intFlags;
  985 
  986     ASSERT_COND(p_MM);
  987 
  988     intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
  989 
  990     if ( CutBusy( p_MM, base, end ) != E_OK )
  991     {
  992         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  993         return (uint64_t)(0);
  994     }
  995 
  996     if ( AddFree ( p_MM, base, end ) != E_OK )
  997     {
  998         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
  999         return (uint64_t)(0);
 1000     }
 1001 
 1002     /* Adding the deallocated memory size to free memory size */
 1003     p_MM->freeMemSize += size;
 1004 
 1005     XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
 1006 
 1007     return (size);
 1008 }
 1009 
 1010 /*****************************************************************************/
 1011 t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size)
 1012 {
 1013     t_MM        *p_MM = (t_MM *)h_MM;
 1014     t_MemBlock  *p_MemB, *p_NewMemB;
 1015     t_Error     errCode;
 1016     uint32_t    intFlags;
 1017 
 1018     ASSERT_COND(p_MM);
 1019 
 1020     /* find a last block in the list of memory blocks to insert a new
 1021      * memory block
 1022      */
 1023     intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
 1024 
 1025     p_MemB = p_MM->memBlocks;
 1026     while ( p_MemB->p_Next )
 1027     {
 1028         if ( base >= p_MemB->base && base < p_MemB->end )
 1029         {
 1030         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
 1031             RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
 1032         }
 1033         p_MemB = p_MemB->p_Next;
 1034     }
 1035     /* check for a last memory block */
 1036     if ( base >= p_MemB->base && base < p_MemB->end )
 1037     {
 1038         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
 1039         RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
 1040     }
 1041 
 1042     /* create a new memory block */
 1043     if ((p_NewMemB = CreateNewBlock(base, size)) == NULL)
 1044     {
 1045         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
 1046         RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
 1047     }
 1048 
 1049     /* append a new memory block to the end of the list of memory blocks */
 1050     p_MemB->p_Next = p_NewMemB;
 1051 
 1052     /* add a new free block to the free lists */
 1053     errCode = AddFree(p_MM, base, base+size);
 1054     if (errCode)
 1055     {
 1056         XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
 1057         p_MemB->p_Next = 0;
 1058         XX_Free(p_NewMemB);
 1059         return ((t_Error)errCode);
 1060     }
 1061 
 1062     /* Adding the new block size to free memory size */
 1063     p_MM->freeMemSize += size;
 1064 
 1065     XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
 1066 
 1067     return (E_OK);
 1068 }
 1069 
 1070 /*****************************************************************************/
 1071 uint64_t MM_GetMemBlock(t_Handle h_MM, int index)
 1072 {
 1073     t_MM       *p_MM = (t_MM*)h_MM;
 1074     t_MemBlock *p_MemBlock;
 1075     int         i;
 1076 
 1077     ASSERT_COND(p_MM);
 1078 
 1079     p_MemBlock = p_MM->memBlocks;
 1080     for (i=0; i < index; i++)
 1081         p_MemBlock = p_MemBlock->p_Next;
 1082 
 1083     if ( p_MemBlock )
 1084         return (p_MemBlock->base);
 1085     else
 1086         return (uint64_t)ILLEGAL_BASE;
 1087 }
 1088 
 1089 /*****************************************************************************/
 1090 uint64_t MM_GetBase(t_Handle h_MM)
 1091 {
 1092     t_MM       *p_MM = (t_MM*)h_MM;
 1093     t_MemBlock *p_MemBlock;
 1094 
 1095     ASSERT_COND(p_MM);
 1096 
 1097     p_MemBlock = p_MM->memBlocks;
 1098     return  p_MemBlock->base;
 1099 }
 1100 
 1101 /*****************************************************************************/
 1102 bool MM_InRange(t_Handle h_MM, uint64_t addr)
 1103 {
 1104     t_MM       *p_MM = (t_MM*)h_MM;
 1105     t_MemBlock *p_MemBlock;
 1106 
 1107     ASSERT_COND(p_MM);
 1108 
 1109     p_MemBlock = p_MM->memBlocks;
 1110 
 1111     if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end))
 1112         return TRUE;
 1113     else
 1114         return FALSE;
 1115 }
 1116 
 1117 /*****************************************************************************/
 1118 uint64_t MM_GetFreeMemSize(t_Handle h_MM)
 1119 {
 1120     t_MM       *p_MM = (t_MM*)h_MM;
 1121 
 1122     ASSERT_COND(p_MM);
 1123 
 1124     return p_MM->freeMemSize;
 1125 }
 1126 
 1127 /*****************************************************************************/
 1128 void MM_Dump(t_Handle h_MM)
 1129 {
 1130     t_MM        *p_MM = (t_MM *)h_MM;
 1131     t_FreeBlock *p_FreeB;
 1132     t_BusyBlock *p_BusyB;
 1133     int          i;
 1134 
 1135     p_BusyB = p_MM->busyBlocks;
 1136     XX_Print("List of busy blocks:\n");
 1137     while (p_BusyB)
 1138     {
 1139         XX_Print("\t0x%p: (%s: b=0x%llx, e=0x%llx)\n", p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end );
 1140         p_BusyB = p_BusyB->p_Next;
 1141     }
 1142 
 1143     XX_Print("\nLists of free blocks according to alignment:\n");
 1144     for (i=0; i <= MM_MAX_ALIGNMENT; i++)
 1145     {
 1146         XX_Print("%d alignment:\n", (0x1 << i));
 1147         p_FreeB = p_MM->freeBlocks[i];
 1148         while (p_FreeB)
 1149         {
 1150             XX_Print("\t0x%p: (b=0x%llx, e=0x%llx)\n", p_FreeB, p_FreeB->base, p_FreeB->end);
 1151             p_FreeB = p_FreeB->p_Next;
 1152         }
 1153         XX_Print("\n");
 1154     }
 1155 }

Cache object: 82c18a21b5e816d8d0f55a4dd4be9b49


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.