page.c

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

C
1,579
字号

Returns:

  Status. On success, Memory is filled in with the base address allocated

  EFI_INVALID_PARAMETER     - Parameters violate checking rules defined in spec.
  
  EFI_NOT_FOUND             - Could not allocate pages match the requirement.
  
  EFI_OUT_OF_RESOURCES      - No enough pages to allocate.
  
  EFI_SUCCESS               - Pages successfully allocated.

--*/
{
  EFI_STATUS      Status;
  UINT64          Start;
  UINT64          MaxAddress;
  UINTN           Alignment;

  if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) {
    return EFI_INVALID_PARAMETER;
  }

  if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||
       MemoryType == EfiConventionalMemory) {
    return EFI_INVALID_PARAMETER;
  }

  Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;

  if  (MemoryType == EfiACPIReclaimMemory   ||
       MemoryType == EfiACPIMemoryNVS       ||
       MemoryType == EfiRuntimeServicesCode ||
       MemoryType == EfiRuntimeServicesData) {

    Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
  }

  if (Type == AllocateAddress) {
    if ((*Memory & (Alignment - 1)) != 0) {
      return EFI_NOT_FOUND;
    }
  }

  NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
  NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);

  //
  // If this is for below a particular address, then 
  //
  Start = *Memory;
  
  //
  // The max address is the max natively addressable address for the processor
  //
  MaxAddress = EFI_MAX_ADDRESS;
  
  if (Type == AllocateMaxAddress) {
    MaxAddress = Start;
  }

  CoreAcquireMemoryLock ();
  
  //
  // If not a specific address, then find an address to allocate
  //
  if (Type != AllocateAddress) {
    Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
    if (Start == 0) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Done;
    }
  }

  //
  // Convert pages from FreeMemory to the requested type
  //
  Status = CoreConvertPages (Start, NumberOfPages, MemoryType);

Done:
  CoreReleaseMemoryLock ();

  if (!EFI_ERROR (Status)) {
    *Memory = Start;
  }

  return Status;
}



EFI_BOOTSERVICE
EFI_STATUS 
EFIAPI
CoreFreePages (
  IN EFI_PHYSICAL_ADDRESS   Memory,
  IN UINTN                  NumberOfPages
  )
/*++

Routine Description:

  Frees previous allocated pages.

Arguments:

  Memory        - Base address of memory being freed

  NumberOfPages - The number of pages to free

Returns:

  EFI_NOT_FOUND       - Could not find the entry that covers the range
  
  EFI_INVALID_PARAMETER   - Address not aligned
  
  EFI_SUCCESS         -Pages successfully freed.

--*/
{
  EFI_STATUS      Status;
  EFI_LIST_ENTRY  *Link;
  MEMORY_MAP      *Entry;
  UINTN           Alignment;

  //
  // Free the range
  //
  CoreAcquireMemoryLock ();

  //
  // Find the entry that the covers the range
  //
  Entry = NULL;
  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
    Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
    if (Entry->Start <= Memory && Entry->End > Memory) {
        break;
    }
  }
  if (Link == &gMemoryMap) {
    CoreReleaseMemoryLock ();
    return EFI_NOT_FOUND;
  }

  Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;

  if  (Entry->Type == EfiACPIReclaimMemory   ||
       Entry->Type == EfiACPIMemoryNVS       ||
       Entry->Type == EfiRuntimeServicesCode ||
       Entry->Type == EfiRuntimeServicesData) {

    Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;

  }

  if ((Memory & (Alignment - 1)) != 0) {
    CoreReleaseMemoryLock ();
    return EFI_INVALID_PARAMETER;
  }

  NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
  NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);

  Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);

  CoreReleaseMemoryLock ();

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Destroy the contents
  //
  if (Memory < EFI_MAX_ADDRESS) {
    DEBUG_SET_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);
  }
  
  return Status;
}


EFI_BOOTSERVICE
EFI_STATUS
EFIAPI
CoreGetMemoryMap (
  IN OUT UINTN                  *MemoryMapSize,
  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
  OUT UINTN                     *MapKey,
  OUT UINTN                     *DescriptorSize,
  OUT UINT32                    *DescriptorVersion
  )
/*++

Routine Description:

  This function returns a copy of the current memory map. The map is an array of 
  memory descriptors, each of which describes a contiguous block of memory.

Arguments:

  MemoryMapSize     - A pointer to the size, in bytes, of the MemoryMap buffer. On
                      input, this is the size of the buffer allocated by the caller. 
                      On output, it is the size of the buffer returned by the firmware 
                      if the buffer was large enough, or the size of the buffer needed 
                      to contain the map if the buffer was too small.
  MemoryMap         - A pointer to the buffer in which firmware places the current memory map.
  MapKey            - A pointer to the location in which firmware returns the key for the
                      current memory map.
  DescriptorSize    - A pointer to the location in which firmware returns the size, in
                      bytes, of an individual EFI_MEMORY_DESCRIPTOR.
  DescriptorVersion - A pointer to the location in which firmware returns the version
                      number associated with the EFI_MEMORY_DESCRIPTOR.

Returns:

  EFI_SUCCESS           - The memory map was returned in the MemoryMap buffer.       
  EFI_BUFFER_TOO_SMALL  - The MemoryMap buffer was too small. The current buffer size
                          needed to hold the memory map is returned in MemoryMapSize.
  EFI_INVALID_PARAMETER - One of the parameters has an invalid value.                

--*/
{
  EFI_STATUS                        Status;
  UINTN                             Size;  
  UINTN                             BufferSize;  
  UINTN                             NumberOfRuntimeEntries;
  EFI_LIST_ENTRY                    *Link;
  MEMORY_MAP                        *Entry;  
  EFI_GCD_MAP_ENTRY                 *GcdMapEntry;  

  //
  // Make sure the parameters are valid
  //
  if (MemoryMapSize == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  
  CoreAcquireGcdMemoryLock ();
  
  //
  // Count the number of Reserved and MMIO entries that are marked for runtime use
  //
  NumberOfRuntimeEntries = 0;
  for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
    GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
        (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
      if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
        NumberOfRuntimeEntries++;
      }
    }
  }

  Size = sizeof (EFI_MEMORY_DESCRIPTOR);

  //
  // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
  // prevent people from having pointer math bugs in their code.
  // now you have to use *DescriptorSize to make things work.
  //
  Size += sizeof(UINT64) - (Size % sizeof (UINT64));

  if (DescriptorSize != NULL) {
    *DescriptorSize = Size;
  }
  
  if (DescriptorVersion != NULL) {
    *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
  }

  CoreAcquireMemoryLock ();

  //
  // Compute the buffer size needed to fit the entire map
  //
  BufferSize = Size * NumberOfRuntimeEntries;
  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
    BufferSize += Size;
  }

  if (*MemoryMapSize < BufferSize) {
    Status = EFI_BUFFER_TOO_SMALL;
    goto Done;
  }

  if (MemoryMap == NULL) {
    Status = EFI_INVALID_PARAMETER;
    goto Done;
  }

  //
  // Build the map
  //
  EfiCommonLibZeroMem (MemoryMap, Size);
  for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
    ASSERT (Entry->VirtualStart == 0);

    MemoryMap->Type           = Entry->Type;
    MemoryMap->PhysicalStart  = Entry->Start;
    MemoryMap->VirtualStart   = Entry->VirtualStart;
    MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
  
    switch (Entry->Type) {
    case EfiRuntimeServicesCode:
    case EfiRuntimeServicesData:
    case EfiPalCode:
      MemoryMap->Attribute = Entry->Attribute | EFI_MEMORY_RUNTIME;
      break;

    default:
      MemoryMap->Attribute = Entry->Attribute;
      break;
    }
    
    MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
  }

  for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
    GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
        (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
      if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
        
        MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
        MemoryMap->VirtualStart  = 0;
        MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
        MemoryMap->Attribute     = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;

        if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {
          MemoryMap->Type = EfiReservedMemoryType;
        } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
          if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
            MemoryMap->Type = EfiMemoryMappedIOPortSpace;
          } else {
            MemoryMap->Type = EfiMemoryMappedIO;
          }
        }

        MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
      }
    }
  }
  
  Status = EFI_SUCCESS;

Done:

  CoreReleaseMemoryLock ();
  
  CoreReleaseGcdMemoryLock ();
  
  // 
  // Update the map key finally 
  // 
  if (MapKey != NULL) {
    *MapKey = mMemoryMapKey;
  }
  
  *MemoryMapSize = BufferSize;
  
  return Status;
}

VOID *
CoreAllocatePoolPages (
  IN EFI_MEMORY_TYPE    PoolType,
  IN UINTN              NumberOfPages,
  IN UINTN              Alignment
  )
/*++

Routine Description:

  Internal function.  Used by the pool functions to allocate pages
  to back pool allocation requests.

Arguments:

  PoolType      - The type of memory for the new pool pages

  NumberOfPages - No of pages to allocate

  Alignment     - Bits to align.

Returns:

  The allocated memory, or NULL

--*/
{
  EFI_STATUS        Status;
  UINT64            Start;

  //
  // Find the pages to convert
  //
  Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment);

  //
  // Convert it to boot services data
  //
  if (Start == 0) {
    DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));
  } else {
    Status = CoreConvertPages (Start, NumberOfPages, PoolType);
  }

  return (VOID *)(UINTN)Start;
}

VOID
CoreFreePoolPages (
  IN EFI_PHYSICAL_ADDRESS   Memory,
  IN UINTN                  NumberOfPages
  )
/*++

Routine Description:

  Internal function.  Frees pool pages allocated via AllocatePoolPages ()

Arguments:

  Memory        - The base address to free

  NumberOfPages - The number of pages to free

Returns:

  None

--*/
{
  CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
}


EFI_STATUS
CoreTerminateMemoryMap (
  IN UINTN          MapKey
  )
/*++

Routine Description:

  Make sure the memory map is following all the construction rules, 
  it is the last time to check memory map error before exit boot services.

Arguments:

  MapKey        - Memory map key

Returns:

  EFI_INVALID_PARAMETER       - Memory map not consistent with construction rules.
  
  EFI_SUCCESS                 - Valid memory map.

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

  Status = EFI_SUCCESS;

  CoreAcquireMemoryLock ();

  if (MapKey == mMemoryMapKey) {

    //
    // Make sure the memory map is following all the construction rules
    // This is the last chance we will be able to display any messages on
    // the  console devices.
    //

    for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
      Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
      if (Entry->Attribute & EFI_MEMORY_RUNTIME) { 
        if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {
          DEBUG((EFI_D_ERROR, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
          CoreReleaseMemoryLock ();
          return EFI_INVALID_PARAMETER;
        }
        if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
          DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
          CoreReleaseMemoryLock ();
          return EFI_INVALID_PARAMETER;
        }
        if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
          DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
          CoreReleaseMemoryLock ();
          return EFI_INVALID_PARAMETER;
        }
      }
    }

    //
    // The map key they gave us matches what we expect. Fall through and
    // return success. In an ideal world we would clear out all of
    // EfiBootServicesCode and EfiBootServicesData. However this function
    // is not the last one called by ExitBootServices(), so we have to
    // preserve the memory contents.
    //
  } else {
    Status = EFI_INVALID_PARAMETER;
  }

  CoreReleaseMemoryLock ();

  return Status;
}








⌨️ 快捷键说明

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