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