Home | History | Annotate | Download | only in SdBlockIoPei
      1 /** @file
      2 
      3 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      4 
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions
      7 of the BSD License which accompanies this distribution.  The
      8 full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "SdBlockIoPei.h"
     17 
     18 /**
     19   Allocate a block of memory to be used by the buffer pool.
     20 
     21   @param  Pages          How many pages to allocate.
     22 
     23   @return The allocated memory block or NULL if failed.
     24 
     25 **/
     26 SD_PEIM_MEM_BLOCK *
     27 SdPeimAllocMemBlock (
     28   IN  UINTN                    Pages
     29   )
     30 {
     31   SD_PEIM_MEM_BLOCK            *Block;
     32   EFI_STATUS                   Status;
     33   VOID                         *TempPtr;
     34   EFI_PHYSICAL_ADDRESS         Address;
     35 
     36   TempPtr = NULL;
     37   Block   = NULL;
     38 
     39   Status = PeiServicesAllocatePool (sizeof(SD_PEIM_MEM_BLOCK), &TempPtr);
     40   if (EFI_ERROR (Status)) {
     41     return NULL;
     42   }
     43 
     44   ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(SD_PEIM_MEM_BLOCK));
     45 
     46   //
     47   // each bit in the bit array represents SD_PEIM_MEM_UNIT
     48   // bytes of memory in the memory block.
     49   //
     50   ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
     51 
     52   Block = (SD_PEIM_MEM_BLOCK*)(UINTN)TempPtr;
     53   Block->BufLen   = EFI_PAGES_TO_SIZE (Pages);
     54   Block->BitsLen  = Block->BufLen / (SD_PEIM_MEM_UNIT * 8);
     55 
     56   Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
     57   if (EFI_ERROR (Status)) {
     58     return NULL;
     59   }
     60 
     61   ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);
     62 
     63   Block->Bits = (UINT8*)(UINTN)TempPtr;
     64 
     65   Status = PeiServicesAllocatePages (
     66              EfiBootServicesCode,
     67              Pages,
     68              &Address
     69              );
     70   if (EFI_ERROR (Status)) {
     71     return NULL;
     72   }
     73 
     74   ZeroMem ((VOID*)(UINTN)Address, EFI_PAGES_TO_SIZE (Pages));
     75 
     76   Block->Buf  = (UINT8*)((UINTN)Address);
     77   Block->Next = NULL;
     78 
     79   return Block;
     80 }
     81 
     82 /**
     83   Free the memory block from the memory pool.
     84 
     85   @param  Pool           The memory pool to free the block from.
     86   @param  Block          The memory block to free.
     87 
     88 **/
     89 VOID
     90 SdPeimFreeMemBlock (
     91   IN SD_PEIM_MEM_POOL       *Pool,
     92   IN SD_PEIM_MEM_BLOCK      *Block
     93   )
     94 {
     95   ASSERT ((Pool != NULL) && (Block != NULL));
     96 }
     97 
     98 /**
     99   Alloc some memory from the block.
    100 
    101   @param  Block          The memory block to allocate memory from.
    102   @param  Units          Number of memory units to allocate.
    103 
    104   @return The pointer to the allocated memory. If couldn't allocate the needed memory,
    105           the return value is NULL.
    106 
    107 **/
    108 VOID *
    109 SdPeimAllocMemFromBlock (
    110   IN  SD_PEIM_MEM_BLOCK   *Block,
    111   IN  UINTN               Units
    112   )
    113 {
    114   UINTN                   Byte;
    115   UINT8                   Bit;
    116   UINTN                   StartByte;
    117   UINT8                   StartBit;
    118   UINTN                   Available;
    119   UINTN                   Count;
    120 
    121   ASSERT ((Block != 0) && (Units != 0));
    122 
    123   StartByte  = 0;
    124   StartBit   = 0;
    125   Available  = 0;
    126 
    127   for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
    128     //
    129     // If current bit is zero, the corresponding memory unit is
    130     // available, otherwise we need to restart our searching.
    131     // Available counts the consective number of zero bit.
    132     //
    133     if (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
    134       Available++;
    135 
    136       if (Available >= Units) {
    137         break;
    138       }
    139 
    140       SD_PEIM_NEXT_BIT (Byte, Bit);
    141 
    142     } else {
    143       SD_PEIM_NEXT_BIT (Byte, Bit);
    144 
    145       Available  = 0;
    146       StartByte  = Byte;
    147       StartBit   = Bit;
    148     }
    149   }
    150 
    151   if (Available < Units) {
    152     return NULL;
    153   }
    154 
    155   //
    156   // Mark the memory as allocated
    157   //
    158   Byte  = StartByte;
    159   Bit   = StartBit;
    160 
    161   for (Count = 0; Count < Units; Count++) {
    162     ASSERT (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
    163 
    164     Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) SD_PEIM_MEM_BIT (Bit));
    165     SD_PEIM_NEXT_BIT (Byte, Bit);
    166   }
    167 
    168   return Block->Buf + (StartByte * 8 + StartBit) * SD_PEIM_MEM_UNIT;
    169 }
    170 
    171 /**
    172   Insert the memory block to the pool's list of the blocks.
    173 
    174   @param  Head           The head of the memory pool's block list.
    175   @param  Block          The memory block to insert.
    176 
    177 **/
    178 VOID
    179 SdPeimInsertMemBlockToPool (
    180   IN SD_PEIM_MEM_BLOCK      *Head,
    181   IN SD_PEIM_MEM_BLOCK      *Block
    182   )
    183 {
    184   ASSERT ((Head != NULL) && (Block != NULL));
    185   Block->Next = Head->Next;
    186   Head->Next  = Block;
    187 }
    188 
    189 /**
    190   Is the memory block empty?
    191 
    192   @param  Block   The memory block to check.
    193 
    194   @retval TRUE    The memory block is empty.
    195   @retval FALSE   The memory block isn't empty.
    196 
    197 **/
    198 BOOLEAN
    199 SdPeimIsMemBlockEmpty (
    200   IN SD_PEIM_MEM_BLOCK     *Block
    201   )
    202 {
    203   UINTN                    Index;
    204 
    205 
    206   for (Index = 0; Index < Block->BitsLen; Index++) {
    207     if (Block->Bits[Index] != 0) {
    208       return FALSE;
    209     }
    210   }
    211 
    212   return TRUE;
    213 }
    214 
    215 /**
    216   Unlink the memory block from the pool's list.
    217 
    218   @param  Head           The block list head of the memory's pool.
    219   @param  BlockToUnlink  The memory block to unlink.
    220 
    221 **/
    222 VOID
    223 SdPeimUnlinkMemBlock (
    224   IN SD_PEIM_MEM_BLOCK      *Head,
    225   IN SD_PEIM_MEM_BLOCK      *BlockToUnlink
    226   )
    227 {
    228   SD_PEIM_MEM_BLOCK         *Block;
    229 
    230   ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
    231 
    232   for (Block = Head; Block != NULL; Block = Block->Next) {
    233     if (Block->Next == BlockToUnlink) {
    234       Block->Next         = BlockToUnlink->Next;
    235       BlockToUnlink->Next = NULL;
    236       break;
    237     }
    238   }
    239 }
    240 
    241 /**
    242   Initialize the memory management pool for the host controller.
    243 
    244   @param  Private               The Sd Peim driver private data.
    245 
    246   @retval EFI_SUCCESS           The memory pool is initialized.
    247   @retval Others                Fail to init the memory pool.
    248 
    249 **/
    250 EFI_STATUS
    251 SdPeimInitMemPool (
    252   IN  SD_PEIM_HC_PRIVATE_DATA  *Private
    253   )
    254 {
    255   SD_PEIM_MEM_POOL           *Pool;
    256   EFI_STATUS                 Status;
    257   VOID                       *TempPtr;
    258 
    259   TempPtr = NULL;
    260   Pool    = NULL;
    261 
    262   Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr);
    263   if (EFI_ERROR (Status)) {
    264     return EFI_OUT_OF_RESOURCES;
    265   }
    266 
    267   ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL));
    268 
    269   Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr);
    270 
    271   Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES);
    272 
    273   if (Pool->Head == NULL) {
    274     return EFI_OUT_OF_RESOURCES;
    275   }
    276 
    277   Private->Pool = Pool;
    278   return EFI_SUCCESS;
    279 }
    280 
    281 /**
    282   Release the memory management pool.
    283 
    284   @param  Pool                  The memory pool to free.
    285 
    286   @retval EFI_DEVICE_ERROR      Fail to free the memory pool.
    287   @retval EFI_SUCCESS           The memory pool is freed.
    288 
    289 **/
    290 EFI_STATUS
    291 SdPeimFreeMemPool (
    292   IN SD_PEIM_MEM_POOL       *Pool
    293   )
    294 {
    295   SD_PEIM_MEM_BLOCK         *Block;
    296 
    297   ASSERT (Pool->Head != NULL);
    298 
    299   //
    300   // Unlink all the memory blocks from the pool, then free them.
    301   // SdPeimUnlinkMemBlock can't be used to unlink and free the
    302   // first block.
    303   //
    304   for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
    305     SdPeimFreeMemBlock (Pool, Block);
    306   }
    307 
    308   SdPeimFreeMemBlock (Pool, Pool->Head);
    309 
    310   return EFI_SUCCESS;
    311 }
    312 
    313 /**
    314   Allocate some memory from the host controller's memory pool
    315   which can be used to communicate with host controller.
    316 
    317   @param  Pool      The host controller's memory pool.
    318   @param  Size      Size of the memory to allocate.
    319 
    320   @return The allocated memory or NULL.
    321 
    322 **/
    323 VOID *
    324 SdPeimAllocateMem (
    325   IN  SD_PEIM_MEM_POOL       *Pool,
    326   IN  UINTN                  Size
    327   )
    328 {
    329   SD_PEIM_MEM_BLOCK          *Head;
    330   SD_PEIM_MEM_BLOCK          *Block;
    331   SD_PEIM_MEM_BLOCK          *NewBlock;
    332   VOID                       *Mem;
    333   UINTN                      AllocSize;
    334   UINTN                      Pages;
    335 
    336   Mem       = NULL;
    337   AllocSize = SD_PEIM_MEM_ROUND (Size);
    338   Head      = Pool->Head;
    339   ASSERT (Head != NULL);
    340 
    341   //
    342   // First check whether current memory blocks can satisfy the allocation.
    343   //
    344   for (Block = Head; Block != NULL; Block = Block->Next) {
    345     Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT);
    346 
    347     if (Mem != NULL) {
    348       ZeroMem (Mem, Size);
    349       break;
    350     }
    351   }
    352 
    353   if (Mem != NULL) {
    354     return Mem;
    355   }
    356 
    357   //
    358   // Create a new memory block if there is not enough memory
    359   // in the pool. If the allocation size is larger than the
    360   // default page number, just allocate a large enough memory
    361   // block. Otherwise allocate default pages.
    362   //
    363   if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) {
    364     Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
    365   } else {
    366     Pages = SD_PEIM_MEM_DEFAULT_PAGES;
    367   }
    368 
    369   NewBlock = SdPeimAllocMemBlock (Pages);
    370   if (NewBlock == NULL) {
    371     return NULL;
    372   }
    373 
    374   //
    375   // Add the new memory block to the pool, then allocate memory from it
    376   //
    377   SdPeimInsertMemBlockToPool (Head, NewBlock);
    378   Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT);
    379 
    380   if (Mem != NULL) {
    381     ZeroMem (Mem, Size);
    382   }
    383 
    384   return Mem;
    385 }
    386 
    387 /**
    388   Free the allocated memory back to the memory pool.
    389 
    390   @param  Pool           The memory pool of the host controller.
    391   @param  Mem            The memory to free.
    392   @param  Size           The size of the memory to free.
    393 
    394 **/
    395 VOID
    396 SdPeimFreeMem (
    397   IN SD_PEIM_MEM_POOL     *Pool,
    398   IN VOID                 *Mem,
    399   IN UINTN                Size
    400   )
    401 {
    402   SD_PEIM_MEM_BLOCK       *Head;
    403   SD_PEIM_MEM_BLOCK       *Block;
    404   UINT8                   *ToFree;
    405   UINTN                   AllocSize;
    406   UINTN                   Byte;
    407   UINTN                   Bit;
    408   UINTN                   Count;
    409 
    410   Head      = Pool->Head;
    411   AllocSize = SD_PEIM_MEM_ROUND (Size);
    412   ToFree    = (UINT8 *) Mem;
    413 
    414   for (Block = Head; Block != NULL; Block = Block->Next) {
    415     //
    416     // scan the memory block list for the memory block that
    417     // completely contains the memory to free.
    418     //
    419     if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
    420       //
    421       // compute the start byte and bit in the bit array
    422       //
    423       Byte  = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8;
    424       Bit   = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8;
    425 
    426       //
    427       // reset associated bits in bit array
    428       //
    429       for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) {
    430         ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
    431 
    432         Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit));
    433         SD_PEIM_NEXT_BIT (Byte, Bit);
    434       }
    435 
    436       break;
    437     }
    438   }
    439 
    440   //
    441   // If Block == NULL, it means that the current memory isn't
    442   // in the host controller's pool. This is critical because
    443   // the caller has passed in a wrong memory point
    444   //
    445   ASSERT (Block != NULL);
    446 
    447   //
    448   // Release the current memory block if it is empty and not the head
    449   //
    450   if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) {
    451     SdPeimFreeMemBlock (Pool, Block);
    452   }
    453 
    454   return ;
    455 }
    456