Home | History | Annotate | Download | only in PiSmmCore
      1 /** @file
      2   SMM Memory pool management functions.
      3 
      4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials are licensed and made available
      6   under the terms and conditions of the BSD License which accompanies this
      7   distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PiSmmCore.h"
     16 
     17 LIST_ENTRY  mSmmPoolLists[MAX_POOL_INDEX];
     18 //
     19 // To cache the SMRAM base since when Loading modules At fixed address feature is enabled,
     20 // all module is assigned an offset relative the SMRAM base in build time.
     21 //
     22 GLOBAL_REMOVE_IF_UNREFERENCED  EFI_PHYSICAL_ADDRESS       gLoadModuleAtFixAddressSmramBase = 0;
     23 
     24 /**
     25   Called to initialize the memory service.
     26 
     27   @param   SmramRangeCount       Number of SMRAM Regions
     28   @param   SmramRanges           Pointer to SMRAM Descriptors
     29 
     30 **/
     31 VOID
     32 SmmInitializeMemoryServices (
     33   IN UINTN                 SmramRangeCount,
     34   IN EFI_SMRAM_DESCRIPTOR  *SmramRanges
     35   )
     36 {
     37   UINTN                  Index;
     38  	UINT64                 SmmCodeSize;
     39  	UINTN                  CurrentSmramRangesIndex;
     40  	UINT64                 MaxSize;
     41 
     42   //
     43   // Initialize Pool list
     44   //
     45   for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {
     46     InitializeListHead (&mSmmPoolLists[--Index]);
     47   }
     48   CurrentSmramRangesIndex = 0;
     49   //
     50   // If Loadding Module At fixed Address feature is enabled, cache the SMRAM base here
     51   //
     52   if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
     53     //
     54     // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
     55     //
     56     SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
     57 
     58     //
     59     // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
     60     //
     61     for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {
     62       //
     63       // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
     64       //
     65       if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
     66         continue;
     67       }
     68 
     69       if (SmramRanges[Index].CpuStart >= BASE_1MB) {
     70         if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) {
     71           if (SmramRanges[Index].PhysicalSize >= MaxSize) {
     72             MaxSize = SmramRanges[Index].PhysicalSize;
     73             CurrentSmramRangesIndex = Index;
     74           }
     75         }
     76       }
     77     }
     78     gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart;
     79 
     80     //
     81     // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code
     82     // A notable thing is that SMM core is already loaded into this range.
     83     //
     84     SmramRanges[CurrentSmramRangesIndex].CpuStart     = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize;
     85     SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize;
     86   }
     87   //
     88   // Initialize free SMRAM regions
     89   //
     90   for (Index = 0; Index < SmramRangeCount; Index++) {
     91     SmmAddMemoryRegion (
     92       SmramRanges[Index].CpuStart,
     93       SmramRanges[Index].PhysicalSize,
     94       EfiConventionalMemory,
     95       SmramRanges[Index].RegionState
     96       );
     97   }
     98 
     99 }
    100 
    101 /**
    102   Internal Function. Allocate a pool by specified PoolIndex.
    103 
    104   @param  PoolIndex             Index which indicate the Pool size.
    105   @param  FreePoolHdr           The returned Free pool.
    106 
    107   @retval EFI_OUT_OF_RESOURCES   Allocation failed.
    108   @retval EFI_SUCCESS            Pool successfully allocated.
    109 
    110 **/
    111 EFI_STATUS
    112 InternalAllocPoolByIndex (
    113   IN  UINTN             PoolIndex,
    114   OUT FREE_POOL_HEADER  **FreePoolHdr
    115   )
    116 {
    117   EFI_STATUS            Status;
    118   FREE_POOL_HEADER      *Hdr;
    119   EFI_PHYSICAL_ADDRESS  Address;
    120 
    121   ASSERT (PoolIndex <= MAX_POOL_INDEX);
    122   Status = EFI_SUCCESS;
    123   Hdr = NULL;
    124   if (PoolIndex == MAX_POOL_INDEX) {
    125     Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);
    126     if (EFI_ERROR (Status)) {
    127       return EFI_OUT_OF_RESOURCES;
    128     }
    129     Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
    130   } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {
    131     Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
    132     RemoveEntryList (&Hdr->Link);
    133   } else {
    134     Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
    135     if (!EFI_ERROR (Status)) {
    136       Hdr->Header.Size >>= 1;
    137       Hdr->Header.Available = TRUE;
    138       InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);
    139       Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
    140     }
    141   }
    142 
    143   if (!EFI_ERROR (Status)) {
    144     Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
    145     Hdr->Header.Available = FALSE;
    146   }
    147 
    148   *FreePoolHdr = Hdr;
    149   return Status;
    150 }
    151 
    152 /**
    153   Internal Function. Free a pool by specified PoolIndex.
    154 
    155   @param  FreePoolHdr           The pool to free.
    156 
    157   @retval EFI_SUCCESS           Pool successfully freed.
    158 
    159 **/
    160 EFI_STATUS
    161 InternalFreePoolByIndex (
    162   IN FREE_POOL_HEADER  *FreePoolHdr
    163   )
    164 {
    165   UINTN  PoolIndex;
    166 
    167   ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
    168   ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
    169   ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
    170 
    171   PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
    172   FreePoolHdr->Header.Available = TRUE;
    173   ASSERT (PoolIndex < MAX_POOL_INDEX);
    174   InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);
    175   return EFI_SUCCESS;
    176 }
    177 
    178 /**
    179   Allocate pool of a particular type.
    180 
    181   @param  PoolType               Type of pool to allocate.
    182   @param  Size                   The amount of pool to allocate.
    183   @param  Buffer                 The address to return a pointer to the allocated
    184                                  pool.
    185 
    186   @retval EFI_INVALID_PARAMETER  PoolType not valid.
    187   @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
    188   @retval EFI_SUCCESS            Pool successfully allocated.
    189 
    190 **/
    191 EFI_STATUS
    192 EFIAPI
    193 SmmInternalAllocatePool (
    194   IN   EFI_MEMORY_TYPE  PoolType,
    195   IN   UINTN            Size,
    196   OUT  VOID             **Buffer
    197   )
    198 {
    199   POOL_HEADER           *PoolHdr;
    200   FREE_POOL_HEADER      *FreePoolHdr;
    201   EFI_STATUS            Status;
    202   EFI_PHYSICAL_ADDRESS  Address;
    203   UINTN                 PoolIndex;
    204 
    205   if (PoolType != EfiRuntimeServicesCode &&
    206       PoolType != EfiRuntimeServicesData) {
    207     return EFI_INVALID_PARAMETER;
    208   }
    209 
    210   Size += sizeof (*PoolHdr);
    211   if (Size > MAX_POOL_SIZE) {
    212     Size = EFI_SIZE_TO_PAGES (Size);
    213     Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
    214     if (EFI_ERROR (Status)) {
    215       return Status;
    216     }
    217 
    218     PoolHdr = (POOL_HEADER*)(UINTN)Address;
    219     PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
    220     PoolHdr->Available = FALSE;
    221     *Buffer = PoolHdr + 1;
    222     return Status;
    223   }
    224 
    225   Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
    226   PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
    227   if ((Size & (Size - 1)) != 0) {
    228     PoolIndex++;
    229   }
    230 
    231   Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
    232   if (!EFI_ERROR(Status)) {
    233     *Buffer = &FreePoolHdr->Header + 1;
    234   }
    235   return Status;
    236 }
    237 
    238 /**
    239   Allocate pool of a particular type.
    240 
    241   @param  PoolType               Type of pool to allocate.
    242   @param  Size                   The amount of pool to allocate.
    243   @param  Buffer                 The address to return a pointer to the allocated
    244                                  pool.
    245 
    246   @retval EFI_INVALID_PARAMETER  PoolType not valid.
    247   @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
    248   @retval EFI_SUCCESS            Pool successfully allocated.
    249 
    250 **/
    251 EFI_STATUS
    252 EFIAPI
    253 SmmAllocatePool (
    254   IN   EFI_MEMORY_TYPE  PoolType,
    255   IN   UINTN            Size,
    256   OUT  VOID             **Buffer
    257   )
    258 {
    259   EFI_STATUS  Status;
    260 
    261   Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
    262   if (!EFI_ERROR (Status)) {
    263     SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer);
    264   }
    265   return Status;
    266 }
    267 
    268 /**
    269   Frees pool.
    270 
    271   @param  Buffer                 The allocated pool entry to free.
    272 
    273   @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
    274   @retval EFI_SUCCESS            Pool successfully freed.
    275 
    276 **/
    277 EFI_STATUS
    278 EFIAPI
    279 SmmInternalFreePool (
    280   IN VOID  *Buffer
    281   )
    282 {
    283   FREE_POOL_HEADER  *FreePoolHdr;
    284 
    285   if (Buffer == NULL) {
    286     return EFI_INVALID_PARAMETER;
    287   }
    288 
    289   FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
    290   ASSERT (!FreePoolHdr->Header.Available);
    291 
    292   if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
    293     ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
    294     ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
    295     return SmmInternalFreePages (
    296              (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
    297              EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
    298              );
    299   }
    300   return InternalFreePoolByIndex (FreePoolHdr);
    301 }
    302 
    303 /**
    304   Frees pool.
    305 
    306   @param  Buffer                 The allocated pool entry to free.
    307 
    308   @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
    309   @retval EFI_SUCCESS            Pool successfully freed.
    310 
    311 **/
    312 EFI_STATUS
    313 EFIAPI
    314 SmmFreePool (
    315   IN VOID  *Buffer
    316   )
    317 {
    318   EFI_STATUS  Status;
    319 
    320   Status = SmmInternalFreePool (Buffer);
    321   if (!EFI_ERROR (Status)) {
    322     SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, 0, 0, Buffer);
    323   }
    324   return Status;
    325 }
    326