page.c

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

C
1,579
字号

Returns:

  None

--*/
{
  MEMORY_MAP      *Entry;
  MEMORY_MAP      *Entry2;
  EFI_LIST_ENTRY  *Link2;

  ASSERT_LOCKED (&gMemoryLock);

  //
  // If already freeing the map stack, then return
  //
  if (mFreeMapStack) {
    return ;
  }

  //
  // Move the temporary memory descriptor stack into pool
  //
  mFreeMapStack += 1;

  while (mMapDepth) {

    //
    // Allocate memory for a entry
    //
    Entry = CoreAllocatePoolI (EfiRuntimeServicesData, sizeof(MEMORY_MAP));
    
    ASSERT (Entry);

    //
    // Update to proper entry
    //
    mMapDepth -= 1;

    if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {

      //
      // Move this entry to general pool
      //
      RemoveEntryList (&mMapStack[mMapDepth].Link);
      mMapStack[mMapDepth].Link.ForwardLink = NULL;

      *Entry = mMapStack[mMapDepth];
      Entry->FromPool = TRUE;

      //
      // Find insertion location
      //
      for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
        Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
        if (Entry2->FromPool && Entry2->Start > Entry->Start) {
          break;
        }
      }

      InsertTailList (Link2, &Entry->Link);

    } else {

      //
      // It was removed, don't move it
      //
      CoreFreePoolI (Entry);

    }
  }

  mFreeMapStack -= 1;
}

STATIC
VOID
RemoveMemoryMapEntry (
  MEMORY_MAP      *Entry
  )
/*++

Routine Description:

  Internal function.  Removes a descriptor entry.

Arguments:

  Entry   - The entry to remove

Returns:

  None

--*/
{
  RemoveEntryList (&Entry->Link);
  Entry->Link.ForwardLink = NULL;

  if (Entry->FromPool) {
    CoreFreePoolI (Entry);
  }
}


STATIC
EFI_STATUS
CoreConvertPages (
  IN UINT64           Start,
  IN UINT64           NumberOfPages,
  IN EFI_MEMORY_TYPE  NewType
  )
/*++

Routine Description:

  Internal function.  Converts a memory range to the specified type.
  The range must exist in the memory map.

Arguments:

  Start         - The first address of the range
                  Must be page aligned

  NumberOfPages - The number of pages to convert

  NewType       - The new type for the memory range

Returns:

  EFI_INVALID_PARAMETER   - Invalid parameter
  
  EFI_NOT_FOUND           - Could not find a descriptor cover the specified range 
                            or convertion not allowed.
  
  EFI_SUCCESS             - Successfully converts the memory range to the specified type.

--*/
{

  UINT64          NumberOfBytes;
  UINT64          End;
  UINT64          RangeEnd;
  UINT64          Attribute;
  EFI_LIST_ENTRY  *Link;
  MEMORY_MAP      *Entry;

  Entry = NULL;
  NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
  End = Start + NumberOfBytes - 1;

  ASSERT (NumberOfPages);
  ASSERT ((Start & EFI_PAGE_MASK) == 0);
  ASSERT (End > Start) ;
  ASSERT_LOCKED (&gMemoryLock);

  if (NumberOfPages == 0 || (Start & EFI_PAGE_MASK ) || (Start > (Start + NumberOfBytes))) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Convert the entire range
  //

  while (Start < End) {

    //
    // Find the entry that the covers the range
    //
    for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
      Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);

      if (Entry->Start <= Start && Entry->End > Start) {
        break;
      }
    }

    if (Link == &gMemoryMap) {
      DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
      return EFI_NOT_FOUND;
    }

    //
    // Convert range to the end, or to the end of the descriptor
    // if that's all we've got
    //
    RangeEnd = End;
    if (Entry->End < End) {
      RangeEnd = Entry->End;
    }

    DEBUG ((EFI_D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, (UINTN)NewType));

    //
    // Debug code - verify conversion is allowed
    //
    if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
      DEBUG ((EFI_D_ERROR , "ConvertPages: Incompatible memory types\n"));
      return EFI_NOT_FOUND;
    }  

    //
    // Update counters for the number of pages allocated to each memory type
    //
    if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {
      if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && 
          Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {
        if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
          mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
        } else {
          mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
        }
      }
    }

    if (NewType >= 0 && NewType < EfiMaxMemoryType) {
      if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {
        mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
        if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > 
            gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
          gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
        }
      }
    }

    //
    // Pull range out of descriptor
    //
    if (Entry->Start == Start) {
      
      //
      // Clip start
      //
      Entry->Start = RangeEnd + 1;

    } else if (Entry->End == RangeEnd) {
      
      //
      // Clip end
      //
      Entry->End = Start - 1;

    } else {

      //
      // Pull it out of the center, clip current
      //
      
      //
      // Add a new one
      //
      mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
      mMapStack[mMapDepth].FromPool  = FALSE;
      mMapStack[mMapDepth].Type      = Entry->Type;
      mMapStack[mMapDepth].Start     = RangeEnd+1;
      mMapStack[mMapDepth].End       = Entry->End;

      //
      // Inherit Attribute from the Memory Descriptor that is being clipped
      //
      mMapStack[mMapDepth].Attribute = Entry->Attribute;

      Entry->End = Start - 1;
      ASSERT (Entry->Start < Entry->End);

      Entry = &mMapStack[mMapDepth];
      InsertTailList (&gMemoryMap, &Entry->Link);

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

    //
    // The new range inherits the same Attribute as the Entry 
    //it is being cut out of
    //
    Attribute = Entry->Attribute;

    //
    // If the descriptor is empty, then remove it from the map
    //
    if (Entry->Start == Entry->End + 1) {
      RemoveMemoryMapEntry (Entry);
      Entry = NULL;
    }
    
    //
    // Add our new range in
    //
    CoreAddRange (NewType, Start, RangeEnd, Attribute);

    //
    // Move any map descriptor stack to general pool
    //
    CoreFreeMemoryMapStack ();

    //
    // Bump the starting address, and convert the next range
    //
    Start = RangeEnd + 1;
  }

  //
  // Converted the whole range, done
  //

  return EFI_SUCCESS;
}


STATIC
UINT64
CoreFindFreePagesI (
  IN UINT64           MaxAddress,
  IN UINT64           NumberOfPages,
  IN EFI_MEMORY_TYPE  NewType,
  IN UINTN            Alignment
  )
/*++

Routine Description:

  Internal function. Finds a consecutive free page range below
  the requested address.

Arguments:

  MaxAddress    - The address that the range must be below

  NumberOfPages - Number of pages needed

  NewType       - The type of memory the range is going to be turned into

  Alignment     - Bits to align with

Returns:

  The base address of the range, or 0 if the range was not found

--*/
{
  UINT64          NumberOfBytes;
  UINT64          Target;
  UINT64          DescStart;
  UINT64          DescEnd;
  UINT64          DescNumberOfBytes;
  EFI_LIST_ENTRY  *Link;
  MEMORY_MAP      *Entry;

  if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
    return 0;
  }

  if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
    
    //
    // If MaxAddress is not aligned to the end of a page
    //
    
    //
    // Change MaxAddress to be 1 page lower
    //
    MaxAddress -= (EFI_PAGE_MASK + 1);
    
    //
    // Set MaxAddress to a page boundary
    //
    MaxAddress &= ~EFI_PAGE_MASK;
    
    //
    // Set MaxAddress to end of the page
    //
    MaxAddress |= EFI_PAGE_MASK;
  }

  NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
  Target = 0;

  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
  
    //
    // If it's not a free entry, don't bother with it
    //
    if (Entry->Type != EfiConventionalMemory) {
      continue;
    }

    DescStart = Entry->Start;
    DescEnd = Entry->End;

    //
    // If desc is past max allowed address, skip it
    //
    if (DescStart >= MaxAddress) {
      continue;
    }

    //
    // If desc ends past max allowed address, clip the end
    //
    if (DescEnd >= MaxAddress) {
      DescEnd = MaxAddress;
    }

    DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;

    //
    // Compute the number of bytes we can used from this 
    // descriptor, and see it's enough to satisfy the request
    //
    DescNumberOfBytes = DescEnd - DescStart + 1;

    if (DescNumberOfBytes >= NumberOfBytes) {

      //
      // If this is the best match so far remember it
      //
      if (DescEnd > Target) {
        Target = DescEnd;
      }
    }
  }          

  //
  // If this is a grow down, adjust target to be the allocation base
  //
  Target -= NumberOfBytes - 1;

  //
  // If we didn't find a match, return 0
  //
  if ((Target & EFI_PAGE_MASK) != 0) {
    return 0;
  }

  return Target;
}

STATIC
UINT64
FindFreePages (
    IN UINT64           MaxAddress,
    IN UINT64           NoPages,
    IN EFI_MEMORY_TYPE  NewType,
    IN UINTN            Alignment
    )
/*++

Routine Description:

    Internal function.  Finds a consecutive free page range below
    the requested address

Arguments:

    MaxAddress          - The address that the range must be below

    NoPages             - Number of pages needed

    NewType             - The type of memory the range is going to be turned into

    Alignment           - Bits to align with

Returns:

    The base address of the range, or 0 if the range was not found.

--*/
{
  UINT64  NewMaxAddress;
  UINT64  Start;

  NewMaxAddress = MaxAddress;

  if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
    NewMaxAddress  = mMemoryTypeStatistics[NewType].MaximumAddress;
  } else {
    if (NewMaxAddress > mDefaultMaximumAddress) {
      NewMaxAddress  = mDefaultMaximumAddress;
    }
  }

  Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);
  if (!Start) {
    Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
    if (!Start) {
      //
      // Here means there may be no enough memory to use, so try to go through
      // all the memory descript to promote the untested memory directly
      //
      PromoteMemoryResource ();

      //
      // Allocate memory again after the memory resource re-arranged
      //
      Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
    }
  }

  return Start;
}

EFI_BOOTSERVICE
EFI_STATUS
EFIAPI
CoreAllocatePages (
  IN EFI_ALLOCATE_TYPE      Type,
  IN EFI_MEMORY_TYPE        MemoryType,
  IN UINTN                  NumberOfPages,
  IN OUT EFI_PHYSICAL_ADDRESS  *Memory
  )
/*++

Routine Description:

  Allocates pages from the memory map.

Arguments:

  Type          - The type of allocation to perform

  MemoryType    - The type of memory to turn the allocated pages into

  NumberOfPages - The number of pages to allocate

  Memory        - A pointer to receive the base allocated memory address

⌨️ 快捷键说明

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