Home | History | Annotate | Download | only in Memory
      1 /** @file
      2   EFI PEI Core memory services
      3 
      4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this 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 "PeiMain.h"
     16 
     17 /**
     18 
     19   Initialize the memory services.
     20 
     21   @param PrivateData     Points to PeiCore's private instance data.
     22   @param SecCoreData     Points to a data structure containing information about the PEI core's operating
     23                          environment, such as the size and location of temporary RAM, the stack location and
     24                          the BFV location.
     25   @param OldCoreData     Pointer to the PEI Core data.
     26                          NULL if being run in non-permament memory mode.
     27 
     28 **/
     29 VOID
     30 InitializeMemoryServices (
     31   IN PEI_CORE_INSTANCE           *PrivateData,
     32   IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,
     33   IN PEI_CORE_INSTANCE           *OldCoreData
     34   )
     35 {
     36 
     37   PrivateData->SwitchStackSignal    = FALSE;
     38 
     39   //
     40   // First entering PeiCore, following code will initialized some field
     41   // in PeiCore's private data according to hand off data from sec core.
     42   //
     43   if (OldCoreData == NULL) {
     44 
     45     PrivateData->PeiMemoryInstalled = FALSE;
     46     PrivateData->HobList.Raw        = SecCoreData->PeiTemporaryRamBase;
     47 
     48     PeiCoreBuildHobHandoffInfoTable (
     49       BOOT_WITH_FULL_CONFIGURATION,
     50       (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,
     51       (UINTN) SecCoreData->PeiTemporaryRamSize
     52       );
     53 
     54     //
     55     // Set Ps to point to ServiceTableShadow in Cache
     56     //
     57     PrivateData->Ps = &(PrivateData->ServiceTableShadow);
     58   }
     59 
     60   return;
     61 }
     62 
     63 /**
     64 
     65   This function registers the found memory configuration with the PEI Foundation.
     66 
     67   The usage model is that the PEIM that discovers the permanent memory shall invoke this service.
     68   This routine will hold discoveried memory information into PeiCore's private data,
     69   and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,
     70   PeiDispatcher will migrate temporary memory to permenement memory.
     71 
     72   @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
     73   @param MemoryBegin        Start of memory address.
     74   @param MemoryLength       Length of memory.
     75 
     76   @return EFI_SUCCESS Always success.
     77 
     78 **/
     79 EFI_STATUS
     80 EFIAPI
     81 PeiInstallPeiMemory (
     82   IN CONST EFI_PEI_SERVICES  **PeiServices,
     83   IN EFI_PHYSICAL_ADDRESS    MemoryBegin,
     84   IN UINT64                  MemoryLength
     85   )
     86 {
     87   PEI_CORE_INSTANCE                     *PrivateData;
     88 
     89   DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));
     90   PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
     91 
     92   //
     93   // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.
     94   // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and
     95   // simply return EFI_SUCESS in release tip to ignore it.
     96   //
     97   if (PrivateData->PeiMemoryInstalled) {
     98     DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
     99     ASSERT (FALSE);
    100     return EFI_SUCCESS;
    101   }
    102 
    103   PrivateData->PhysicalMemoryBegin   = MemoryBegin;
    104   PrivateData->PhysicalMemoryLength  = MemoryLength;
    105   PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;
    106 
    107   PrivateData->SwitchStackSignal      = TRUE;
    108 
    109   return EFI_SUCCESS;
    110 }
    111 
    112 /**
    113   The purpose of the service is to publish an interface that allows
    114   PEIMs to allocate memory ranges that are managed by the PEI Foundation.
    115 
    116   @param  PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
    117   @param  MemoryType       The type of memory to allocate.
    118   @param  Pages            The number of contiguous 4 KB pages to allocate.
    119   @param  Memory           Pointer to a physical address. On output, the address is set to the base
    120                            of the page range that was allocated.
    121 
    122   @retval EFI_SUCCESS           The memory range was successfully allocated.
    123   @retval EFI_OUT_OF_RESOURCES  The pages could not be allocated.
    124   @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
    125                                 EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
    126                                 EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
    127 
    128 **/
    129 EFI_STATUS
    130 EFIAPI
    131 PeiAllocatePages (
    132   IN CONST EFI_PEI_SERVICES     **PeiServices,
    133   IN       EFI_MEMORY_TYPE      MemoryType,
    134   IN       UINTN                Pages,
    135   OUT      EFI_PHYSICAL_ADDRESS *Memory
    136   )
    137 {
    138   PEI_CORE_INSTANCE                       *PrivateData;
    139   EFI_PEI_HOB_POINTERS                    Hob;
    140   EFI_PHYSICAL_ADDRESS                    *FreeMemoryTop;
    141   EFI_PHYSICAL_ADDRESS                    *FreeMemoryBottom;
    142   UINTN                                   RemainingPages;
    143 
    144   if ((MemoryType != EfiLoaderCode) &&
    145       (MemoryType != EfiLoaderData) &&
    146       (MemoryType != EfiRuntimeServicesCode) &&
    147       (MemoryType != EfiRuntimeServicesData) &&
    148       (MemoryType != EfiBootServicesCode) &&
    149       (MemoryType != EfiBootServicesData) &&
    150       (MemoryType != EfiACPIReclaimMemory) &&
    151       (MemoryType != EfiReservedMemoryType) &&
    152       (MemoryType != EfiACPIMemoryNVS)) {
    153     return EFI_INVALID_PARAMETER;
    154   }
    155 
    156   PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
    157   Hob.Raw     = PrivateData->HobList.Raw;
    158 
    159   //
    160   // Check if Hob already available
    161   //
    162   if (!PrivateData->PeiMemoryInstalled) {
    163     //
    164     // When PeiInstallMemory is called but temporary memory has *not* been moved to temporary memory,
    165     // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.
    166     //
    167     if (!PrivateData->SwitchStackSignal) {
    168       return EFI_NOT_AVAILABLE_YET;
    169     } else {
    170       FreeMemoryTop     = &(PrivateData->FreePhysicalMemoryTop);
    171       FreeMemoryBottom  = &(PrivateData->PhysicalMemoryBegin);
    172     }
    173   } else {
    174     FreeMemoryTop     = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
    175     FreeMemoryBottom  = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);
    176   }
    177 
    178   //
    179   // Check to see if on 4k boundary, If not aligned, make the allocation aligned.
    180   //
    181   *(FreeMemoryTop) -= *(FreeMemoryTop) & 0xFFF;
    182 
    183   //
    184   // Verify that there is sufficient memory to satisfy the allocation.
    185   // For page allocation, the overhead sizeof (EFI_HOB_MEMORY_ALLOCATION) needs to be considered.
    186   //
    187   if ((UINTN) (*FreeMemoryTop - *FreeMemoryBottom) < (UINTN) ALIGN_VALUE (sizeof (EFI_HOB_MEMORY_ALLOCATION), 8)) {
    188     DEBUG ((EFI_D_ERROR, "AllocatePages failed: No space to build memory allocation hob.\n"));
    189     return  EFI_OUT_OF_RESOURCES;
    190   }
    191   RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom - ALIGN_VALUE (sizeof (EFI_HOB_MEMORY_ALLOCATION), 8)) >> EFI_PAGE_SHIFT;
    192   //
    193   // The number of remaining pages needs to be greater than or equal to that of the request pages.
    194   //
    195   if (RemainingPages < Pages) {
    196     DEBUG ((EFI_D_ERROR, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64) Pages));
    197     DEBUG ((EFI_D_ERROR, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64) RemainingPages));
    198     return  EFI_OUT_OF_RESOURCES;
    199   } else {
    200     //
    201     // Update the PHIT to reflect the memory usage
    202     //
    203     *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;
    204 
    205     //
    206     // Update the value for the caller
    207     //
    208     *Memory = *(FreeMemoryTop);
    209 
    210     //
    211     // Create a memory allocation HOB.
    212     //
    213     BuildMemoryAllocationHob (
    214       *(FreeMemoryTop),
    215       Pages * EFI_PAGE_SIZE,
    216       MemoryType
    217       );
    218 
    219     return EFI_SUCCESS;
    220   }
    221 }
    222 
    223 /**
    224 
    225   Pool allocation service. Before permanent memory is discoveried, the pool will
    226   be allocated the heap in the temporary memory. Genenrally, the size of heap in temporary
    227   memory does not exceed to 64K, so the biggest pool size could be allocated is
    228   64K.
    229 
    230   @param PeiServices               An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
    231   @param Size                      Amount of memory required
    232   @param Buffer                    Address of pointer to the buffer
    233 
    234   @retval EFI_SUCCESS              The allocation was successful
    235   @retval EFI_OUT_OF_RESOURCES     There is not enough heap to satisfy the requirement
    236                                    to allocate the requested size.
    237 
    238 **/
    239 EFI_STATUS
    240 EFIAPI
    241 PeiAllocatePool (
    242   IN CONST EFI_PEI_SERVICES     **PeiServices,
    243   IN       UINTN                Size,
    244   OUT      VOID                 **Buffer
    245   )
    246 {
    247   EFI_STATUS               Status;
    248   EFI_HOB_MEMORY_POOL      *Hob;
    249 
    250   //
    251   // If some "post-memory" PEIM wishes to allocate larger pool,
    252   // it should use AllocatePages service instead.
    253   //
    254 
    255   //
    256   // Generally, the size of heap in temporary memory does not exceed to 64K,
    257   // HobLength is multiples of 8 bytes, so the maxmium size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
    258   //
    259   if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
    260     return EFI_OUT_OF_RESOURCES;
    261   }
    262 
    263   Status = PeiServicesCreateHob (
    264              EFI_HOB_TYPE_MEMORY_POOL,
    265              (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
    266              (VOID **)&Hob
    267              );
    268   ASSERT_EFI_ERROR (Status);
    269   *Buffer = Hob+1;
    270 
    271   return Status;
    272 }
    273