gcd.c

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

C
2,443
字号
  CoreMergeGcdMapEntry (EndLink, TRUE, Map);

  return EFI_SUCCESS;
}

EFI_STATUS
CoreSearchGcdMapEntry (
  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
  IN  UINT64                Length,
  OUT EFI_LIST_ENTRY        **StartLink,
  OUT EFI_LIST_ENTRY        **EndLink,
  IN  EFI_LIST_ENTRY        *Map
  )
/*++

Routine Description:

  Search a segment of memory space in GCD map. The result is a range of GCD entry list.

Arguments:

  BaseAddress       - The start address of the segment.
  
  Length            - The length of the segment.
  
  StartLink         - The first GCD entry involves this segment of memory space.
  
  EndLink           - The first GCD entry involves this segment of memory space.
  
  Map               - Points to the start entry to search.

Returns:

  EFI_SUCCESS       - Successfully found the entry.
  
  EFI_NOT_FOUND     - Not found.

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

  ASSERT (Length != 0);

  *StartLink = NULL;
  *EndLink   = NULL;

  Link = Map->ForwardLink;
  while (Link != Map) {
    Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    if (BaseAddress >= Entry->BaseAddress && BaseAddress <= Entry->EndAddress) {
      *StartLink = Link;
    }
    if (*StartLink != NULL) {
      if ((BaseAddress + Length - 1) >= Entry->BaseAddress && 
          (BaseAddress + Length - 1) <= Entry->EndAddress     ) {
        *EndLink = Link;
        return EFI_SUCCESS;
      }
    }
    Link = Link->ForwardLink;
  }
  return EFI_NOT_FOUND;
}

UINTN
CoreCountGcdMapEntry (
  IN EFI_LIST_ENTRY  *Map
  )
/*++

Routine Description:

  Count the amount of GCD map entries.

Arguments:

  Map       - Points to the start entry to do the count loop.

Returns:

  The count.

--*/
{
  UINTN           Count;
  EFI_LIST_ENTRY  *Link;

  Count = 0;
  Link = Map->ForwardLink;
  while (Link != Map) {
    Count++;
    Link = Link->ForwardLink;
  }
  return Count;
}



UINT64
ConverToCpuArchAttributes (
  UINT64 Attributes
  ) 
/*++

Routine Description:

  Return the memory attribute specified by Attributes

Arguments:

  Attributes        - A num with some attribute bits on.

Returns:

  The enum value of memory attribute.

--*/
{
  if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
    return EFI_MEMORY_UC;
  }

  if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) {
    return EFI_MEMORY_WC;
  }

  if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) {
    return EFI_MEMORY_WT;
  }

  if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {
    return EFI_MEMORY_WB;
  }

  if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {
    return EFI_MEMORY_WP;
  }

  return INVALID_CPU_ARCH_ATTRIBUTES;

}


EFI_STATUS
CoreConvertSpace (
  IN UINTN                 Operation,
  IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,
  IN EFI_GCD_IO_TYPE       GcdIoType,
  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
  IN UINT64                Length,
  IN UINT64                Capabilities,
  IN UINT64                Attributes
  )
/*++

Routine Description:

  Do operation on a segment of memory space specified (add, free, remove, change attribute ...).

Arguments:

  Operation       - The type of the operation
  
  GcdMemoryType   - Additional information for the operation
  
  GcdIoType       - Additional information for the operation
  
  BaseAddress     - Start address of the segment
  
  Length          - length of the segment
  
  Capabilities    - The alterable attributes of a newly added entry
  
  Attributes      - The attributes needs to be set
  
Returns:

  EFI_INVALID_PARAMETER       - Length is 0 or address (length) not aligned when setting attribute.
  
  EFI_SUCCESS                 - Action successfully done.
  
  EFI_UNSUPPORTED             - Could not find the proper descriptor on this segment or 
                                set an upsupported attribute.
  
  EFI_ACCESS_DENIED           - Operate on an space non-exist or is used for an image.
  
  EFI_NOT_FOUND               - Free a non-using space or remove a non-exist space, and so on.
  
  EFI_OUT_OF_RESOURCES        - No buffer could be allocated.

Returns:

--*/
{
  EFI_STATUS         Status;
  EFI_LIST_ENTRY     *Map;
  EFI_LIST_ENTRY     *Link;
  EFI_GCD_MAP_ENTRY  *Entry;
  EFI_GCD_MAP_ENTRY  *TopEntry;
  EFI_GCD_MAP_ENTRY  *BottomEntry;
  EFI_LIST_ENTRY     *StartLink;
  EFI_LIST_ENTRY     *EndLink;
  
  EFI_CPU_ARCH_PROTOCOL           *CpuArch;
  UINT64                          CpuArchAttributes;

  if (Length == 0) {
    return EFI_INVALID_PARAMETER;
  }

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

  //
  // 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_UNSUPPORTED;

    goto Done;
  }

  //
  // Verify that the list of descriptors are unallocated non-existent memory.
  //
  Link = StartLink;
  while (Link != EndLink->ForwardLink) {
    Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
    switch (Operation) {
    //
    // Add operations
    //
    case GCD_ADD_MEMORY_OPERATION:
      if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent ||
          Entry->ImageHandle   != NULL                           ) {
        Status = EFI_ACCESS_DENIED;
        goto Done;
      }
      break;
    case GCD_ADD_IO_OPERATION:
      if (Entry->GcdIoType   != EfiGcdIoTypeNonExistent ||
          Entry->ImageHandle != NULL                       ) {
        Status = EFI_ACCESS_DENIED;
        goto Done;
      }
      break;
    //
    // Free operations
    //
    case GCD_FREE_MEMORY_OPERATION:
    case GCD_FREE_IO_OPERATION:
      if (Entry->ImageHandle == NULL) {
        Status = EFI_NOT_FOUND;
        goto Done;
      }
      break;
    //
    // Remove operations
    //
    case GCD_REMOVE_MEMORY_OPERATION:
      if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
        Status = EFI_NOT_FOUND;
        goto Done;
      }
      if (Entry->ImageHandle != NULL) {
        Status = EFI_ACCESS_DENIED;
        goto Done;
      }
      break;
    case GCD_REMOVE_IO_OPERATION:
      if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
        Status = EFI_NOT_FOUND;
        goto Done;
      }
      if (Entry->ImageHandle != NULL) {
        Status = EFI_ACCESS_DENIED;
        goto Done;
      }
      break;
    //
    // Set attribute operations
    //
    case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
      if (Attributes & EFI_MEMORY_RUNTIME) {
        if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
          Status = EFI_INVALID_PARAMETER;

          goto Done;
        }
      }
      if ((Entry->Capabilities & Attributes) != Attributes) {
        Status = EFI_UNSUPPORTED;
        goto Done;
      }
      break;
    }
    Link = Link->ForwardLink;
  }

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

  //
  //
  //
  if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
    //
    // Call CPU Arch Protocol to attempt to set attributes on the range
    //
    CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
    if ( CpuArchAttributes != INVALID_CPU_ARCH_ATTRIBUTES ) {
      Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, &CpuArch);
      if (EFI_ERROR (Status)) {
        Status = EFI_ACCESS_DENIED;
        goto Done;
      }

      Status = CpuArch->SetMemoryAttributes (
                          CpuArch,
                          BaseAddress,
                          Length,
                          CpuArchAttributes
                          );
      if (EFI_ERROR (Status)) {
        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);
    switch (Operation) {
    //
    // Add operations
    //
    case GCD_ADD_MEMORY_OPERATION:
      Entry->GcdMemoryType = GcdMemoryType;
      if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
        Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
      } else {
        Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;
      }
      break;
    case GCD_ADD_IO_OPERATION:
      Entry->GcdIoType = GcdIoType;
      break;
    //
    // Free operations
    //
    case GCD_FREE_MEMORY_OPERATION:
    case GCD_FREE_IO_OPERATION:
      Entry->ImageHandle  = NULL;
      Entry->DeviceHandle = NULL;
      break;
    //
    // Remove operations
    //
    case GCD_REMOVE_MEMORY_OPERATION:
      Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
      Entry->Capabilities  = 0;
      break;
    case GCD_REMOVE_IO_OPERATION:
      Entry->GcdIoType = EfiGcdIoTypeNonExistent;
      break;
    //
    // Set attribute operations
    //
    case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
      Entry->Attributes = Attributes;
      break;
    }
    Link = Link->ForwardLink;
  }

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

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

  return Status;
}

EFI_STATUS
CoreAllocateSpaceCheckEntry (
  IN UINTN                Operation,
  IN EFI_GCD_MAP_ENTRY    *Entry,
  IN EFI_GCD_MEMORY_TYPE  GcdMemoryType,
  IN EFI_GCD_IO_TYPE      GcdIoType
  )
/*++

Routine Description:

  Check whether an entry could be used to allocate space.

Arguments:

  Operation       - Allocate memory or IO
  
  Entry           - The entry to be tested
  
  GcdMemoryType   - The desired memory type
  
  GcdIoType       - The desired IO type
  
Returns:

  EFI_NOT_FOUND   - The memory type does not match or there's an image handle on the entry.
  
  EFI_UNSUPPORTED - The operation unsupported.
  
  EFI_SUCCESS     - It's ok for this entry to be used to allocate space.

--*/
{
  if (Entry->ImageHandle != NULL) {
    return EFI_NOT_FOUND;
  }
  switch (Operation) {
  case GCD_ALLOCATE_MEMORY_OPERATION:
    if (Entry->GcdMemoryType != GcdMemoryType) {
      return EFI_NOT_FOUND;
    }
    break;
  case GCD_ALLOCATE_IO_OPERATION:
    if (Entry->GcdIoType != GcdIoType) {
      return EFI_NOT_FOUND;
    }
    break;
  default:
    return EFI_UNSUPPORTED;
  }
  return EFI_SUCCESS;
}

EFI_STATUS
CoreAllocateSpace (
  IN     UINTN                  Operation,
  IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,
  IN     EFI_GCD_MEMORY_TYPE    GcdMemoryType,
  IN     EFI_GCD_IO_TYPE        GcdIoType,
  IN     UINTN                  Alignment,
  IN     UINT64                 Length,
  IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,
  IN     EFI_HANDLE             ImageHandle,
  IN     EFI_HANDLE             DeviceHandle OPTIONAL
  )
/*++

Routine Description:

  Allocate space on specified address and length.

Arguments:

  Operation         - The type of operation (memory or IO)
  GcdAllocateType   - The type of allocate operation
  GcdMemoryType     - The desired memory type
  GcdIoType         - The desired IO type
  Alignment         - Align with 2^Alignment

⌨️ 快捷键说明

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