page.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,579 行 · 第 1/3 页

C
1,579
字号
/*++

Copyright (c) 2004 - 2006, Intel Corporation                                                         
All rights reserved. This program and the accompanying materials                          
are licensed and made available under the terms and conditions of the BSD License         
which accompanies this distribution.  The full text of the license may be found at        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             

Module Name:

  page.c

Abstract:

  EFI Memory page management


Revision History

--*/

#include "imem.h"

#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT  (EFI_PAGE_SIZE)

//
// Entry for tracking the memory regions for each memory type to help cooalese like memory types
//
typedef struct {
  EFI_PHYSICAL_ADDRESS  BaseAddress;
  EFI_PHYSICAL_ADDRESS  MaximumAddress;
  UINT64                CurrentNumberOfPages;
  UINTN                 InformationIndex;
} EFI_MEMORY_TYPE_STAISTICS;

//
// MemoryMap - The current memory map
//
UINTN     mMemoryMapKey = 0;

//
// mMapStack - space to use as temp storage to build new map descriptors
// mMapDepth - depth of new descriptor stack
//

#define MAX_MAP_DEPTH 6
UINTN         mMapDepth = 0;
MEMORY_MAP    mMapStack[MAX_MAP_DEPTH];
UINTN         mFreeMapStack = 0;

BOOLEAN mMemoryTypeInformationInitialized = FALSE;

EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiReservedMemoryType
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiLoaderCode
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiLoaderData
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiBootServicesCode
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiBootServicesData
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiRuntimeServicesCode
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiRuntimeServicesData
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiConventionalMemory
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiUnusableMemory
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiACPIReclaimMemory
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiACPIMemoryNVS
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiMemoryMappedIO
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiMemoryMappedIOPortSpace
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType },  // EfiPalCode
  { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }   // EfiMaxMemoryType
};

EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;

EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
  { EfiReservedMemoryType,      0 },
  { EfiLoaderCode,              0 },
  { EfiLoaderData,              0 },
  { EfiBootServicesCode,        0 },
  { EfiBootServicesData,        0 },
  { EfiRuntimeServicesCode,     0 },
  { EfiRuntimeServicesData,     0 },
  { EfiConventionalMemory,      0 },
  { EfiUnusableMemory,          0 },
  { EfiACPIReclaimMemory,       0 },
  { EfiACPIMemoryNVS,           0 },
  { EfiMemoryMappedIO,          0 },
  { EfiMemoryMappedIOPortSpace, 0 },
  { EfiPalCode,                 0 },
  { EfiMaxMemoryType,           0 }
};

//
// Internal prototypes
//
VOID 
PromoteMemoryResource (
  VOID
);

STATIC
VOID
CoreAddRange (
  IN EFI_MEMORY_TYPE          Type,
  IN EFI_PHYSICAL_ADDRESS     Start,
  IN EFI_PHYSICAL_ADDRESS     End,
  IN UINT64                   Attribute
  );

STATIC
VOID
CoreFreeMemoryMapStack (
  VOID
  );

STATIC
EFI_STATUS
CoreConvertPages (
  IN UINT64           Start,
  IN UINT64           NumberOfPages,
  IN EFI_MEMORY_TYPE  NewType
  );

STATIC
VOID
RemoveMemoryMapEntry (
  MEMORY_MAP      *Entry
  );

VOID
CoreAcquireMemoryLock (
  VOID
  )
/*++

Routine Description:

  Enter critical section by gaining lock on gMemoryLock

Arguments:

  None

Returns:

  None

--*/
{
  CoreAcquireLock (&gMemoryLock);
}


VOID
CoreReleaseMemoryLock (
  VOID
  )
/*++

Routine Description:

  Exit critical section by releasing lock on gMemoryLock

Arguments:

  None

Returns:

  None

--*/
{
  CoreReleaseLock (&gMemoryLock);
}

VOID
PromoteMemoryResource (
  VOID
  )
/*++

Routine Description:

  Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.

Arguments:

  None

Returns:

  None

--*/
{
  EFI_LIST_ENTRY                   *Link;
  EFI_GCD_MAP_ENTRY                *Entry;

  DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "Promote the memory resource\n"));
  
  CoreAcquireGcdMemoryLock ();
  
  Link = mGcdMemorySpaceMap.ForwardLink;
  while (Link != &mGcdMemorySpaceMap) {

    Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);

    if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
        Entry->EndAddress < EFI_MAX_ADDRESS &&
        (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
          (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
      //
      // Update the GCD map
      //
      Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
      Entry->Capabilities |= EFI_MEMORY_TESTED;
      Entry->ImageHandle  = gDxeCoreImageHandle;
      Entry->DeviceHandle = NULL;

      //
      // Add to allocable system memory resource
      //      

      CoreAddRange (
        EfiConventionalMemory, 
        Entry->BaseAddress, 
        Entry->EndAddress, 
        Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
        );
      CoreFreeMemoryMapStack ();
      
    }

    Link = Link->ForwardLink;
  }
  
  CoreReleaseGcdMemoryLock ();
  
  return;
}

VOID
CoreAddMemoryDescriptor (
  IN EFI_MEMORY_TYPE       Type,
  IN EFI_PHYSICAL_ADDRESS  Start,
  IN UINT64                NumberOfPages,
  IN UINT64                Attribute
  )
/*++

Routine Description:

  Called to initialize the memory map and add descriptors to
  the current descriptor list.

  N.B. The first descriptor that is added must be general usable
  memory as the addition allocates heap.

Arguments:

  Type          - The type of memory to add

  Start         - The starting address in the memory range
                  Must be page aligned

  NumberOfPages - The number of pages in the range

  Attribute     - Attributes of the memory to add

Returns:

  None.  The range is added to the memory map

--*/
{
  EFI_PHYSICAL_ADDRESS        End;
  EFI_STATUS                  Status;
  UINTN                       Index;
  UINTN                       FreeIndex;

  if ((Start & EFI_PAGE_MASK) != 0) {
    return;
  }

  if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {
    return;
  }
  
  CoreAcquireMemoryLock ();
  End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
  CoreAddRange (Type, Start, End, Attribute);
  CoreFreeMemoryMapStack ();
  CoreReleaseMemoryLock ();

  //
  // Check to see if the statistics for the different memory types have already been established
  //
  if (mMemoryTypeInformationInitialized) {
    return;
  }

  //
  // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
  //
  for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
    //
    // Make sure the memory type in the gMemoryTypeInformation[] array is valid
    //
    Type = gMemoryTypeInformation[Index].Type;
    if (Type < 0 || Type > EfiMaxMemoryType) {
      continue;
    }

    if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
      //
      // Allocate pages for the current memory type from the top of available memory
      //
      Status = CoreAllocatePages (
                 AllocateAnyPages,
                 Type,
                 gMemoryTypeInformation[Index].NumberOfPages,
                 &mMemoryTypeStatistics[Type].BaseAddress
                 );
      if (EFI_ERROR (Status)) {
        //
        // If an error occurs allocating the pages for the current memory type, then 
        // free all the pages allocates for the previous memory types and return.  This
        // operation with be retied when/if more memory is added to the system
        //
        for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
          //
          // Make sure the memory type in the gMemoryTypeInformation[] array is valid
          //
          Type = gMemoryTypeInformation[FreeIndex].Type;
          if (Type < 0 || Type > EfiMaxMemoryType) {
            continue;
          }

          if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
            CoreFreePages (
              mMemoryTypeStatistics[Type].BaseAddress, 
              gMemoryTypeInformation[FreeIndex].NumberOfPages
              );
            mMemoryTypeStatistics[Type].BaseAddress    = 0;
            mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;
          }
        }
        return;
      }

      //
      // Compute the address at the top of the current statistics
      //
      mMemoryTypeStatistics[Type].MaximumAddress = 
        mMemoryTypeStatistics[Type].BaseAddress + 
        LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;

      //
      // If the current base address is the lowest address so far, then update the default 
      // maximum address
      //
      if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
        mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
      }
    }
  }

  //
  // There was enough system memory for all the the memory types were allocated.  So,
  // those memory areas can be freed for future allocations, and all future memory
  // allocations can occur within their respective bins
  //
  for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
    //
    // Make sure the memory type in the gMemoryTypeInformation[] array is valid
    //
    Type = gMemoryTypeInformation[Index].Type;
    if (Type < 0 || Type > EfiMaxMemoryType) {
      continue;
    }

    if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
      CoreFreePages (
        mMemoryTypeStatistics[Type].BaseAddress, 
        gMemoryTypeInformation[Index].NumberOfPages
        );
      gMemoryTypeInformation[Index].NumberOfPages = 0;
    }
  }

  //
  // If the number of pages reserved for a memory type is 0, then all allocations for that type
  // should be in the default range.
  //
  for (Type = 0; Type < EfiMaxMemoryType; Type++) {
    for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
      if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
        mMemoryTypeStatistics[Type].InformationIndex = Index;
      }
    }
    mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
    if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {
      mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
    }
  }

  mMemoryTypeInformationInitialized = TRUE;
}


STATIC
VOID
CoreAddRange (
  IN EFI_MEMORY_TYPE        Type,
  IN EFI_PHYSICAL_ADDRESS     Start,
  IN EFI_PHYSICAL_ADDRESS     End,
  IN UINT64           Attribute
  )
/*++

Routine Description:

  Internal function.  Adds a ranges to the memory map.
  The range must not already exist in the map.

Arguments:

  Type    - The type of memory range to add

  Start   - The starting address in the memory range
            Must be paged aligned

  End     - The last address in the range
          Must be the last byte of a page

  Attribute - The attributes of the memory range to add

Returns:

  None.  The range is added to the memory map

--*/
{
  EFI_LIST_ENTRY    *Link;
  MEMORY_MAP        *Entry;

  ASSERT ((Start & EFI_PAGE_MASK) == 0);
  ASSERT (End > Start) ;

  ASSERT_LOCKED (&gMemoryLock);
  
  DEBUG ((EFI_D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, (UINTN)Type));

  //
  // Memory map being altered
  //

  mMemoryMapKey += 1;
  
  //
  // Look for adjoining memory descriptor
  //
  
  // Two memory descriptors can only be merged if they have the same Type
  // and the same Attribute
  //

  Link = gMemoryMap.ForwardLink;
  while (Link != &gMemoryMap) {
    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
    Link  = Link->ForwardLink;

    if (Entry->Type != Type) {
      continue;
    }

    if (Entry->Attribute != Attribute) {
      continue;
    }

    if (Entry->End + 1 == Start) {
      
      Start = Entry->Start;
      RemoveMemoryMapEntry (Entry);

    } else if (Entry->Start == End + 1) {
      
      End = Entry->End;
      RemoveMemoryMapEntry (Entry);
    }
  }

  //
  // Add descriptor 
  //

  mMapStack[mMapDepth].Signature     = MEMORY_MAP_SIGNATURE;
  mMapStack[mMapDepth].FromPool      = FALSE;
  mMapStack[mMapDepth].Type          = Type;
  mMapStack[mMapDepth].Start         = Start;
  mMapStack[mMapDepth].End           = End;
  mMapStack[mMapDepth].VirtualStart  = 0;
  mMapStack[mMapDepth].Attribute     = Attribute;
  InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);

  mMapDepth += 1;
  ASSERT (mMapDepth < MAX_MAP_DEPTH);
  return ;
}

STATIC
VOID
CoreFreeMemoryMapStack (
  VOID
  )
/*++

Routine Description:

  Internal function.  Moves any memory descriptors that are on the
  temporary descriptor stack to heap.

Arguments:

  None

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?