gcd.c

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

C
2,443
字号
  Length            - Length to allocate
  BaseAddress       - Base address to allocate
  ImageHandle       - The image handle consume the allocated space.
  DeviceHandle      - The device handle consume the allocated space.

Returns:

  EFI_INVALID_PARAMETER       - Invalid parameter.
  EFI_NOT_FOUND               - No descriptor for the desired space exists.
  EFI_SUCCESS                 - Space successfully allocated.

--*/
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  AlignmentMask;
  EFI_PHYSICAL_ADDRESS  MaxAddress;
  EFI_LIST_ENTRY        *Map;
  EFI_LIST_ENTRY        *Link;
  EFI_LIST_ENTRY        *SubLink;
  EFI_GCD_MAP_ENTRY     *Entry;
  EFI_GCD_MAP_ENTRY     *TopEntry;
  EFI_GCD_MAP_ENTRY     *BottomEntry;
  EFI_LIST_ENTRY        *StartLink;
  EFI_LIST_ENTRY        *EndLink;
  BOOLEAN               Found;

  //
  // Make sure parameters are valid
  //
  if (GcdAllocateType < 0 || GcdAllocateType >= EfiGcdMaxAllocateType) {
    return EFI_INVALID_PARAMETER;
  }
  if (GcdMemoryType < 0 || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
    return EFI_INVALID_PARAMETER;
  }
  if (GcdIoType < 0 || GcdIoType >= EfiGcdIoTypeMaximum) {
    return EFI_INVALID_PARAMETER;
  }
  if (BaseAddress == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  if (ImageHandle == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  if (Alignment >= 64) {
    return EFI_NOT_FOUND;
  }
  if (Length == 0) {
    return EFI_INVALID_PARAMETER;
  }

  Map = NULL;
  if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
    CoreAcquireGcdMemoryLock ();
    Map = &mGcdMemorySpaceMap;
  }
  if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
    CoreAcquireGcdIoLock ();
    Map = &mGcdIoSpaceMap;
  }

  Found     = FALSE;
  StartLink = NULL;
  EndLink   = NULL;
  //
  // Compute alignment bit mask
  //
  AlignmentMask = LShiftU64 (1, Alignment) - 1;

  if (GcdAllocateType == EfiGcdAllocateAddress) {
    //
    // Verify that the BaseAddress passed in is aligned correctly
    //
    if ((*BaseAddress & AlignmentMask) != 0) {
      Status = EFI_NOT_FOUND;
      goto Done;
    }

    //
    // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
    //
    Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
    if (EFI_ERROR (Status)) {
      Status = EFI_NOT_FOUND;
      goto Done;
    }

    //
    // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
    //
    Link = StartLink;
    while (Link != EndLink->ForwardLink) {
      Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
      Link = Link->ForwardLink;
      Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
      if (EFI_ERROR (Status)) {
        goto Done;
      }
    }
    Found = TRUE;
  } else {

    Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);

    //
    // Compute the maximum address to use in the search algorithm
    //
    if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||
        GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown) {
      MaxAddress = *BaseAddress;
    } else {
      MaxAddress = Entry->EndAddress;
    }

    //
    // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
    //
    if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
        GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
      Link = Map->BackLink;
    } else {
      Link = Map->ForwardLink;
    }
    while (Link != Map) {
      Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);

      if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
          GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
        Link = Link->BackLink;
      } else {
        Link = Link->ForwardLink;
      }

      Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
      if (EFI_ERROR (Status)) {
        continue;
      }

      if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
          GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
        if (Entry->BaseAddress > MaxAddress) {
          continue;
        }
        if (Length > (Entry->EndAddress + 1)) {
          Status = EFI_NOT_FOUND;
          goto Done;
        }
        if (Entry->EndAddress > MaxAddress) {
          *BaseAddress = MaxAddress;
        } else {
          *BaseAddress = Entry->EndAddress;
        }
        *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
      } else {
        *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
        if ((*BaseAddress + Length - 1) > MaxAddress) {
          Status = EFI_NOT_FOUND;
          goto Done;
        }
      }

      //
      // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
      //
      Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
      if (EFI_ERROR (Status)) {
        Status = EFI_NOT_FOUND;
        goto Done;
      }

      Link = StartLink;
      //
      // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
      //
      Found = TRUE;
      SubLink = StartLink;
      while (SubLink != EndLink->ForwardLink) {
        Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
        Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
        if (EFI_ERROR (Status)) {
          Link = SubLink;
          Found = FALSE;
          break;
        }
        SubLink = SubLink->ForwardLink;
      }
      if (Found) {
        break;
      }
    }
  }
  if (!Found) {
    Status = EFI_NOT_FOUND;
    goto Done;
  }

  //
  // Allocate work space to perform this operation
  //
  Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
  if (EFI_ERROR (Status)) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  //
  // Convert/Insert the list of descriptors from StartLink to EndLink
  //
  Link = StartLink;
  while (Link != EndLink->ForwardLink) {
    Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
    Entry->ImageHandle  = ImageHandle;
    Entry->DeviceHandle = DeviceHandle;
    Link = Link->ForwardLink;
  }

  //
  // Cleanup
  //
  Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);

Done:
  if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
    CoreReleaseGcdMemoryLock ();
  }
  if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
    CoreReleaseGcdIoLock ();
  }

  return Status;
}


EFI_STATUS
CoreInternalAddMemorySpace (
  IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,
  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
  IN UINT64                Length,
  IN UINT64                Capabilities
  )
/*++

Routine Description:

  Add a segment of memory to GCD map.

Arguments:

  GcdMemoryType     - Memory type of the segment.
  
  BaseAddress       - Base address of the segment.
  
  Length            - Length of the segment.
  
  Capabilities      - alterable attributes of the segment.

Returns:

  EFI_INVALID_PARAMETER       - Invalid parameters.
  
  EFI_SUCCESS                 - Successfully add a segment of memory space.

--*/
{
  //
  // Make sure parameters are valid
  //
  if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, 0, BaseAddress, Length, Capabilities, 0);
}

//
// GCD Core Services
//
EFI_STATUS
CoreAllocateMemorySpace (
  IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,
  IN     EFI_GCD_MEMORY_TYPE    GcdMemoryType,
  IN     UINTN                  Alignment,
  IN     UINT64                 Length,
  IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,
  IN     EFI_HANDLE             ImageHandle,
  IN     EFI_HANDLE             DeviceHandle OPTIONAL
  )
/*++

Routine Description:

  Allocates nonexistent memory, reserved memory, system memory, or memorymapped
I/O resources from the global coherency domain of the processor.

Arguments:

  GcdAllocateType   - The type of allocate operation
  
  GcdMemoryType     - The desired memory type
  
  Alignment         - Align with 2^Alignment
  
  Length            - Length to allocate
  
  BaseAddress       - Base address to allocate
  
  ImageHandle       - The image handle consume the allocated space.
  
  DeviceHandle      - The device handle consume the allocated space.

Returns:

  EFI_INVALID_PARAMETER       - Invalid parameter.
  
  EFI_NOT_FOUND               - No descriptor contains the desired space.
  
  EFI_SUCCESS                 - Memory space successfully allocated.

--*/
{
  return CoreAllocateSpace (
           GCD_ALLOCATE_MEMORY_OPERATION, 
           GcdAllocateType, 
           GcdMemoryType, 
           0, 
           Alignment, 
           Length, 
           BaseAddress, 
           ImageHandle, 
           DeviceHandle
           );
}

EFI_STATUS
CoreAddMemorySpace (
  IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,
  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
  IN UINT64                Length,
  IN UINT64                Capabilities
  )
/*++

Routine Description:

  Adds reserved memory, system memory, or memory-mapped I/O resources to the
global coherency domain of the processor.

Arguments:

  GcdMemoryType     - Memory type of the memory space.
  
  BaseAddress       - Base address of the memory space.
  
  Length            - Length of the memory space.
  
  Capabilities      - alterable attributes of the memory space.

Returns:

  EFI_SUCCESS       - Merged this memory space into GCD map.  

--*/
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  PageBaseAddress;
  UINT64                PageLength;

  Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);

  if (!EFI_ERROR (Status) && GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {

    PageBaseAddress = PageAlignLength (BaseAddress);
    PageLength      = PageAlignLength (BaseAddress + Length - PageBaseAddress);

    Status = CoreAllocateMemorySpace (
               EfiGcdAllocateAddress,
               GcdMemoryType,
               EFI_PAGE_SHIFT,         
               PageLength,
               &PageBaseAddress,
               gDxeCoreImageHandle,
               NULL
               );

    if (!EFI_ERROR (Status)) {
      CoreAddMemoryDescriptor (
        EfiConventionalMemory,
        PageBaseAddress,
        RShiftU64 (PageLength, EFI_PAGE_SHIFT),
        Capabilities
        );
    } else {
      for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
        Status = CoreAllocateMemorySpace (
                   EfiGcdAllocateAddress,
                   GcdMemoryType,
                   EFI_PAGE_SHIFT,         
                   EFI_PAGE_SIZE,
                   &PageBaseAddress,
                   gDxeCoreImageHandle,
                   NULL
                   );

        if (!EFI_ERROR (Status)) {
          CoreAddMemoryDescriptor (
            EfiConventionalMemory,
            PageBaseAddress,
            1,
            Capabilities
            );
        }
      }
    }
  }
  return Status;
}

EFI_STATUS
CoreFreeMemorySpace (
  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
  IN UINT64                Length
  )
/*++

Routine Description:

  Frees nonexistent memory, reserved memory, system memory, or memory-mapped
I/O resources from the global coherency domain of the processor.

Arguments:

  BaseAddress       - Base address of the memory space.
  
  Length            - Length of the memory space.
  
Returns:

  EFI_SUCCESS       - Space successfully freed.

--*/
{
  return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, 0);
}

EFI_STATUS
CoreRemoveMemorySpace (
  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
  IN UINT64                Length
  )
/*++

Routine Description:

  Removes reserved memory, system memory, or memory-mapped I/O resources from
the global coherency domain of the processor.

Arguments:

  BaseAddress       - Base address of the memory space.
  
  Length            - Length of the memory space.
  
Returns:

  EFI_SUCCESS       - Successfully remove a segment of memory space.

--*/
{
  return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, 0, 0, BaseAddress, Length, 0, 0);
}

VOID
BuildMemoryDescriptor (
  IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor,
  IN EFI_GCD_MAP_ENTRY                *Entry
  )
/*++

Routine Description:

  Build a memory descriptor according to an entry.

Arguments:

  Descriptor          - The descriptor to be built
  
  Entry               - According to this entry

⌨️ 快捷键说明

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