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 + -
显示快捷键?