gcd.c

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

C
2,443
字号
/*++

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:

    gcd.c

Abstract:

    The file contains the GCD related services in the EFI Boot Services Table.
    The GCD services are used to manage the memory and I/O regions that 
    are accessible to the CPU that is executing the DXE core.

--*/

#include "gcd.h"

#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000

#define MEMORY_ATTRIBUTE_MASK         (EFI_RESOURCE_ATTRIBUTE_PRESENT             | \
                                       EFI_RESOURCE_ATTRIBUTE_INITIALIZED         | \
                                       EFI_RESOURCE_ATTRIBUTE_TESTED              | \
                                       EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED      | \
                                       EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED     | \
                                       EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
                                       EFI_RESOURCE_ATTRIBUTE_16_BIT_IO           | \
                                       EFI_RESOURCE_ATTRIBUTE_32_BIT_IO           | \
                                       EFI_RESOURCE_ATTRIBUTE_64_BIT_IO           ) 

#define TESTED_MEMORY_ATTRIBUTES      (EFI_RESOURCE_ATTRIBUTE_PRESENT     | \
                                       EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
                                       EFI_RESOURCE_ATTRIBUTE_TESTED      )

#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT     | \
                                       EFI_RESOURCE_ATTRIBUTE_INITIALIZED )

#define PRESENT_MEMORY_ATTRIBUTES     (EFI_RESOURCE_ATTRIBUTE_PRESENT)

#define INVALID_CPU_ARCH_ATTRIBUTES   0xffffffff

//
// Module Variables
//
EFI_LOCK           mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY);
EFI_LOCK           mGcdIoSpaceLock     = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_NOTIFY);
EFI_LIST_ENTRY     mGcdMemorySpaceMap  = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);
EFI_LIST_ENTRY     mGcdIoSpaceMap      = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);

EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {
  EFI_GCD_MAP_SIGNATURE,
  { NULL, NULL },
  0,
  0,
  0,
  0,
  EfiGcdMemoryTypeNonExistent,
  0,
  NULL,
  NULL
};

EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
  EFI_GCD_MAP_SIGNATURE,
  { NULL, NULL },
  0,
  0,
  0,
  0,
  0,
  EfiGcdIoTypeNonExistent,
  NULL,
  NULL
};

GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
  { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE,             EFI_MEMORY_UC,          TRUE  },
  { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED,       EFI_MEMORY_UCE,         TRUE  },   
  { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE,       EFI_MEMORY_WC,          TRUE  },
  { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT,          TRUE  },
  { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE,    EFI_MEMORY_WB,          TRUE  },
  { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED,          EFI_MEMORY_RP,          TRUE  },
  { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED,         EFI_MEMORY_WP,          TRUE  },
  { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED,     EFI_MEMORY_XP,          TRUE  },
  { EFI_RESOURCE_ATTRIBUTE_PRESENT,                 EFI_MEMORY_PRESENT,     FALSE },
  { EFI_RESOURCE_ATTRIBUTE_INITIALIZED,             EFI_MEMORY_INITIALIZED, FALSE },
  { EFI_RESOURCE_ATTRIBUTE_TESTED,                  EFI_MEMORY_TESTED,      FALSE },
  { 0, 0, FALSE }
};

VOID
CoreAcquireGcdMemoryLock (
  VOID
  )
/*++

Routine Description:
    Acquire memory lock on mGcdMemorySpaceLock

Arguments:
    None

Returns:
    None

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


VOID
CoreReleaseGcdMemoryLock (
  VOID
  )
/*++

Routine Description:
    Release memory lock on mGcdMemorySpaceLock

Arguments:
    None

Returns:
    None

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



VOID
CoreAcquireGcdIoLock (
  VOID
  )
/*++

Routine Description:
    Acquire memory lock on mGcdIoSpaceLock

Arguments:
    None

Returns:
    None

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


VOID
CoreReleaseGcdIoLock (
  VOID
  )
/*++

Routine Description:
    Release memory lock on mGcdIoSpaceLock

Arguments:
    None

Returns:
    None

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



//
// GCD Initialization Worker Functions
//
UINT64
AlignValue (
  IN UINT64   Value,
  IN UINTN    Alignment,
  IN BOOLEAN  RoundUp
  )
/*++

Routine Description:

  Aligns a value to the specified boundary.

Arguments:

  Value     - 64 bit value to align
  Alignment - Log base 2 of the boundary to align Value to
  RoundUp   - TRUE if Value is to be rounded up to the nearest aligned boundary. 
              FALSE is Value is to be rounded down to the nearest aligned boundary.

Returns:

  A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.

--*/
{
  UINT64  AlignmentMask;

  AlignmentMask = LShiftU64 (1, Alignment) - 1;
  if (RoundUp) {
    Value += AlignmentMask;
  }
  return Value & (~AlignmentMask);
}

UINT64
PageAlignAddress (
  IN UINT64 Value
  )
/*++

Routine Description:

  Aligns address to the page boundary.

Arguments:

  Value     - 64 bit address to align

Returns:

  A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.

--*/
{
  return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);
}

UINT64
PageAlignLength (
  IN UINT64 Value
  )
/*++

Routine Description:

  Aligns length to the page boundary.

Arguments:

  Value     - 64 bit length to align

Returns:

  A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.

--*/
{
  return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);
}

//
// GCD Memory Space Worker Functions
//
EFI_STATUS
CoreAllocateGcdMapEntry (
  IN OUT EFI_GCD_MAP_ENTRY  **TopEntry,
  IN OUT EFI_GCD_MAP_ENTRY  **BottomEntry
  )
/*++

Routine Description:

  Allocate pool for two entries.

Arguments:

  TopEntry      - An entry of GCD map
  BottomEntry   - An entry of GCD map

Returns:

  EFI_OUT_OF_RESOURCES    - No enough buffer to be allocated.
  EFI_SUCCESS             - Both entries successfully allocated.

--*/
{
  *TopEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY));
  if (*TopEntry == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  *BottomEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY));
  if (*BottomEntry == NULL) {
    CoreFreePool (*TopEntry);
    return EFI_OUT_OF_RESOURCES;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
CoreInsertGcdMapEntry (
  IN EFI_LIST_ENTRY        *Link,
  IN EFI_GCD_MAP_ENTRY     *Entry,
  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
  IN UINT64                Length,
  IN EFI_GCD_MAP_ENTRY     *TopEntry,
  IN EFI_GCD_MAP_ENTRY     *BottomEntry
  )
/*++

Routine Description:

  Internal function.  Inserts a new descriptor into a sorted list

Arguments:

  Link        - The linked list to insert the range BaseAddress and Length into

  Entry     -   A pointer to the entry that is inserted

  BaseAddress - The base address of the new range
  
  Length      - The length of the new range in bytes
  
  TopEntry    - Top pad entry to insert if needed.

  BottomEntry - Bottom pad entry to insert if needed.

Returns:

  EFI_SUCCESS - The new range was inserted into the linked list
  
--*/
{
  ASSERT (Length != 0);
  ASSERT (TopEntry->Signature == 0);
  ASSERT (BottomEntry->Signature == 0);

  if (BaseAddress > Entry->BaseAddress) {
    EfiCommonLibCopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
    Entry->BaseAddress      = BaseAddress;
    BottomEntry->EndAddress = BaseAddress - 1;
    InsertTailList (Link, &BottomEntry->Link);
  } 

  if ((BaseAddress + Length - 1) < Entry->EndAddress) {
    EfiCommonLibCopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
    TopEntry->BaseAddress = BaseAddress + Length;
    Entry->EndAddress     = BaseAddress + Length - 1;
    InsertHeadList (Link, &TopEntry->Link);
  }

  return EFI_SUCCESS;
}

EFI_STATUS
CoreMergeGcdMapEntry (
  IN EFI_LIST_ENTRY  *Link,
  IN BOOLEAN         Forward,
  IN EFI_LIST_ENTRY  *Map
  )
/*++

Routine Description:

  Merge the Gcd region specified by Link and its adjacent entry

Arguments:

  Link      - Specify the entry to be merged (with its adjacent entry).
  
  Forward   - Direction (forward or backward).
  
  Map       - Boundary.

Returns:

  EFI_SUCCESS     - Successfully returned.
  
  EFI_UNSUPPORTED - These adjacent regions could not merge.

--*/
{
  EFI_LIST_ENTRY     *AdjacentLink;
  EFI_GCD_MAP_ENTRY  *Entry;
  EFI_GCD_MAP_ENTRY  *AdjacentEntry;

  //
  // Get adjacent entry
  //
  if (Forward) {
    AdjacentLink = Link->ForwardLink;
  } else {
    AdjacentLink = Link->BackLink;
  }

  //
  // If AdjacentLink is the head of the list, then no merge can be performed
  //
  if (AdjacentLink == Map) {
    return EFI_SUCCESS;
  }

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

  if (Entry->Capabilities != AdjacentEntry->Capabilities) {
    return EFI_UNSUPPORTED;
  }
  if (Entry->Attributes != AdjacentEntry->Attributes) {
    return EFI_UNSUPPORTED;
  }
  if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {
    return EFI_UNSUPPORTED;
  }
  if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {
    return EFI_UNSUPPORTED;
  }
  if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {
    return EFI_UNSUPPORTED;
  }
  if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {
    return EFI_UNSUPPORTED;
  }

  if (Forward) {
    Entry->EndAddress  = AdjacentEntry->EndAddress;
  } else {
    Entry->BaseAddress = AdjacentEntry->BaseAddress;
  }
  RemoveEntryList (AdjacentLink);
  CoreFreePool (AdjacentEntry);

  return EFI_SUCCESS;
}

EFI_STATUS
CoreCleanupGcdMapEntry (
  IN EFI_GCD_MAP_ENTRY  *TopEntry,
  IN EFI_GCD_MAP_ENTRY  *BottomEntry,
  IN EFI_LIST_ENTRY     *StartLink,
  IN EFI_LIST_ENTRY     *EndLink,
  IN EFI_LIST_ENTRY     *Map
  )
/*++

Routine Description:

  Merge adjacent entries on total chain.

Arguments:

  TopEntry      - Top entry of GCD map.
  
  BottomEntry   - Bottom entry of GCD map.
  
  StartLink     - Start link of the list for this loop.
  
  EndLink       - End link of the list for this loop.
  
  Map           - Boundary.

Returns:

  EFI_SUCCESS   - GCD map successfully cleaned up.

--*/
{
  EFI_LIST_ENTRY  *Link;

  if (TopEntry->Signature == 0) {
    CoreFreePool (TopEntry);
  }
  if (BottomEntry->Signature == 0) {
    CoreFreePool (BottomEntry);
  }

  Link = StartLink;
  while (Link != EndLink->ForwardLink) {
    CoreMergeGcdMapEntry (Link, FALSE, Map);
    Link = Link->ForwardLink;
  }

⌨️ 快捷键说明

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