X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FGcd%2FGcd.c;h=907245a3f512c2eeb5424cdf166744b57c1df2ce;hp=bff13b3bf666148325e72545e0045c12932b0cfe;hb=5b91bf82c67b586b9588cbe4bbffa1588f6b5926;hpb=924c766d6f5da3aa4219deccc6feaaa33c636953 diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index bff13b3bf6..907245a3f5 100644 --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c @@ -1,21 +1,22 @@ -/** @file +/** @file + 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. - 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. +Copyright (c) 2006 - 2017, 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 -Copyright (c) 2006 - 2008, 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. +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ -#include +#include "DxeMain.h" +#include "Gcd.h" +#include "Mem/HeapGuard.h" #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000 @@ -25,9 +26,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \ EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \ EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \ - EFI_RESOURCE_ATTRIBUTE_64_BIT_IO ) + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_PERSISTENT ) #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ @@ -38,6 +41,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT) +#define EXCLUSIVE_MEMORY_ATTRIBUTES (EFI_MEMORY_UC | EFI_MEMORY_WC | \ + EFI_MEMORY_WT | EFI_MEMORY_WB | \ + EFI_MEMORY_WP | EFI_MEMORY_UCE) + +#define NONEXCLUSIVE_MEMORY_ATTRIBUTES (EFI_MEMORY_XP | EFI_MEMORY_RP | \ + EFI_MEMORY_RO) + #define INVALID_CPU_ARCH_ATTRIBUTES 0xffffffff // @@ -50,7 +60,10 @@ LIST_ENTRY mGcdIoSpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSp EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = { EFI_GCD_MAP_SIGNATURE, - { NULL, NULL }, + { + NULL, + NULL + }, 0, 0, 0, @@ -63,7 +76,10 @@ EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = { EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = { EFI_GCD_MAP_SIGNATURE, - { NULL, NULL }, + { + NULL, + NULL + }, 0, 0, 0, @@ -75,20 +91,166 @@ EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = { }; 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 } + { 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_PROTECTABLE, EFI_MEMORY_RP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE, EFI_MEMORY_WP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE, EFI_MEMORY_XP, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE, EFI_MEMORY_RO, 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 }, + { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE, EFI_MEMORY_NV, TRUE }, + { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE, EFI_MEMORY_MORE_RELIABLE, TRUE }, + { 0, 0, FALSE } }; +/// +/// Lookup table used to print GCD Memory Space Map +/// +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = { + "NonExist ", // EfiGcdMemoryTypeNonExistent + "Reserved ", // EfiGcdMemoryTypeReserved + "SystemMem", // EfiGcdMemoryTypeSystemMemory + "MMIO ", // EfiGcdMemoryTypeMemoryMappedIo + "PersisMem", // EfiGcdMemoryTypePersistent + "MoreRelia", // EfiGcdMemoryTypeMoreReliable + "Unknown " // EfiGcdMemoryTypeMaximum +}; + +/// +/// Lookup table used to print GCD I/O Space Map +/// +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdIoTypeNames[] = { + "NonExist", // EfiGcdIoTypeNonExistent + "Reserved", // EfiGcdIoTypeReserved + "I/O ", // EfiGcdIoTypeIo + "Unknown " // EfiGcdIoTypeMaximum +}; + +/// +/// Lookup table used to print GCD Allocation Types +/// +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdAllocationTypeNames[] = { + "AnySearchBottomUp ", // EfiGcdAllocateAnySearchBottomUp + "MaxAddressSearchBottomUp ", // EfiGcdAllocateMaxAddressSearchBottomUp + "AtAddress ", // EfiGcdAllocateAddress + "AnySearchTopDown ", // EfiGcdAllocateAnySearchTopDown + "MaxAddressSearchTopDown ", // EfiGcdAllocateMaxAddressSearchTopDown + "Unknown " // EfiGcdMaxAllocateType +}; + +/** + Dump the entire contents if the GCD Memory Space Map using DEBUG() macros when + PcdDebugPrintErrorLevel has the DEBUG_GCD bit set. + + @param InitialMap TRUE if the initial GCD Memory Map is being dumped. Otherwise, FALSE. + +**/ +VOID +EFIAPI +CoreDumpGcdMemorySpaceMap ( + BOOLEAN InitialMap + ) +{ + DEBUG_CODE ( + EFI_STATUS Status; + UINTN NumberOfDescriptors; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + UINTN Index; + + Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); + ASSERT (Status == EFI_SUCCESS && MemorySpaceMap != NULL); + + if (InitialMap) { + DEBUG ((DEBUG_GCD, "GCD:Initial GCD Memory Space Map\n")); + } + DEBUG ((DEBUG_GCD, "GCDMemType Range Capabilities Attributes \n")); + DEBUG ((DEBUG_GCD, "========== ================================= ================ ================\n")); + for (Index = 0; Index < NumberOfDescriptors; Index++) { + DEBUG ((DEBUG_GCD, "%a %016lx-%016lx %016lx %016lx%c\n", + mGcdMemoryTypeNames[MIN (MemorySpaceMap[Index].GcdMemoryType, EfiGcdMemoryTypeMaximum)], + MemorySpaceMap[Index].BaseAddress, + MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - 1, + MemorySpaceMap[Index].Capabilities, + MemorySpaceMap[Index].Attributes, + MemorySpaceMap[Index].ImageHandle == NULL ? ' ' : '*' + )); + } + DEBUG ((DEBUG_GCD, "\n")); + FreePool (MemorySpaceMap); + ); +} + +/** + Dump the entire contents if the GCD I/O Space Map using DEBUG() macros when + PcdDebugPrintErrorLevel has the DEBUG_GCD bit set. + + @param InitialMap TRUE if the initial GCD I/O Map is being dumped. Otherwise, FALSE. + +**/ +VOID +EFIAPI +CoreDumpGcdIoSpaceMap ( + BOOLEAN InitialMap + ) +{ + DEBUG_CODE ( + EFI_STATUS Status; + UINTN NumberOfDescriptors; + EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap; + UINTN Index; + + Status = CoreGetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap); + ASSERT (Status == EFI_SUCCESS && IoSpaceMap != NULL); + + if (InitialMap) { + DEBUG ((DEBUG_GCD, "GCD:Initial GCD I/O Space Map\n")); + } + + DEBUG ((DEBUG_GCD, "GCDIoType Range \n")); + DEBUG ((DEBUG_GCD, "========== =================================\n")); + for (Index = 0; Index < NumberOfDescriptors; Index++) { + DEBUG ((DEBUG_GCD, "%a %016lx-%016lx%c\n", + mGcdIoTypeNames[MIN (IoSpaceMap[Index].GcdIoType, EfiGcdIoTypeMaximum)], + IoSpaceMap[Index].BaseAddress, + IoSpaceMap[Index].BaseAddress + IoSpaceMap[Index].Length - 1, + IoSpaceMap[Index].ImageHandle == NULL ? ' ' : '*' + )); + } + DEBUG ((DEBUG_GCD, "\n")); + FreePool (IoSpaceMap); + ); +} + +/** + Validate resource descriptor HOB's attributes. + + If Attributes includes some memory resource's settings, it should include + the corresponding capabilites also. + + @param Attributes Resource descriptor HOB attributes. + +**/ +VOID +CoreValidateResourceDescriptorHobAttributes ( + IN UINT64 Attributes + ) +{ + ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED) == 0) || + ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE) != 0)); + ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED) == 0) || + ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE) != 0)); + ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED) == 0) || + ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE) != 0)); + ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED) == 0) || + ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE) != 0)); + ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == 0) || + ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE) != 0)); +} /** Acquire memory lock on mGcdMemorySpaceLock. @@ -122,7 +284,6 @@ CoreReleaseGcdMemoryLock ( Acquire memory lock on mGcdIoSpaceLock. **/ -STATIC VOID CoreAcquireGcdIoLock ( VOID @@ -136,7 +297,6 @@ CoreAcquireGcdIoLock ( Release memory lock on mGcdIoSpaceLock. **/ -STATIC VOID CoreReleaseGcdIoLock ( VOID @@ -150,20 +310,18 @@ CoreReleaseGcdIoLock ( // // GCD Initialization Worker Functions // - /** Aligns a value to the specified boundary. - @param Value 64 bit value to align - @param Alignment Log base 2 of the boundary to align Value to - @param 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. + @param Value 64 bit value to align + @param Alignment Log base 2 of the boundary to align Value to + @param 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. @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. **/ -STATIC UINT64 AlignValue ( IN UINT64 Value, @@ -184,12 +342,11 @@ AlignValue ( /** Aligns address to the page boundary. - @param Value 64 bit address to align + @param Value 64 bit address to align @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. **/ -STATIC UINT64 PageAlignAddress ( IN UINT64 Value @@ -202,12 +359,11 @@ PageAlignAddress ( /** Aligns length to the page boundary. - @param Value 64 bit length to align + @param Value 64 bit length to align @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment. **/ -STATIC UINT64 PageAlignLength ( IN UINT64 Value @@ -223,26 +379,34 @@ PageAlignLength ( /** Allocate pool for two entries. - @param TopEntry An entry of GCD map - @param BottomEntry An entry of GCD map + @param TopEntry An entry of GCD map + @param BottomEntry An entry of GCD map - @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated. + @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated. @retval EFI_SUCCESS Both entries successfully allocated. **/ -STATIC EFI_STATUS CoreAllocateGcdMapEntry ( IN OUT EFI_GCD_MAP_ENTRY **TopEntry, IN OUT EFI_GCD_MAP_ENTRY **BottomEntry ) { - *TopEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY)); + // + // Set to mOnGuarding to TRUE before memory allocation. This will make sure + // that the entry memory is not "guarded" by HeapGuard. Otherwise it might + // cause problem when it's freed (if HeapGuard is enabled). + // + mOnGuarding = TRUE; + *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY)); + mOnGuarding = FALSE; if (*TopEntry == NULL) { return EFI_OUT_OF_RESOURCES; } - *BottomEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_GCD_MAP_ENTRY)); + mOnGuarding = TRUE; + *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY)); + mOnGuarding = FALSE; if (*BottomEntry == NULL) { CoreFreePool (*TopEntry); return EFI_OUT_OF_RESOURCES; @@ -255,18 +419,17 @@ CoreAllocateGcdMapEntry ( /** Internal function. Inserts a new descriptor into a sorted list - @param Link The linked list to insert the range BaseAddress - and Length into - @param Entry A pointer to the entry that is inserted - @param BaseAddress The base address of the new range - @param Length The length of the new range in bytes - @param TopEntry Top pad entry to insert if needed. - @param BottomEntry Bottom pad entry to insert if needed. + @param Link The linked list to insert the range BaseAddress + and Length into + @param Entry A pointer to the entry that is inserted + @param BaseAddress The base address of the new range + @param Length The length of the new range in bytes + @param TopEntry Top pad entry to insert if needed. + @param BottomEntry Bottom pad entry to insert if needed. @retval EFI_SUCCESS The new range was inserted into the linked list **/ -STATIC EFI_STATUS CoreInsertGcdMapEntry ( IN LIST_ENTRY *Link, @@ -278,17 +441,19 @@ CoreInsertGcdMapEntry ( ) { ASSERT (Length != 0); - ASSERT (TopEntry->Signature == 0); - ASSERT (BottomEntry->Signature == 0); if (BaseAddress > Entry->BaseAddress) { + ASSERT (BottomEntry->Signature == 0); + CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY)); Entry->BaseAddress = BaseAddress; BottomEntry->EndAddress = BaseAddress - 1; InsertTailList (Link, &BottomEntry->Link); - } + } if ((BaseAddress + Length - 1) < Entry->EndAddress) { + ASSERT (TopEntry->Signature == 0); + CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY)); TopEntry->BaseAddress = BaseAddress + Length; Entry->EndAddress = BaseAddress + Length - 1; @@ -300,18 +465,17 @@ CoreInsertGcdMapEntry ( /** - Merge the Gcd region specified by Link and its adjacent entry + Merge the Gcd region specified by Link and its adjacent entry. - @param Link Specify the entry to be merged (with its - adjacent entry). - @param Forward Direction (forward or backward). - @param Map Boundary. + @param Link Specify the entry to be merged (with its + adjacent entry). + @param Forward Direction (forward or backward). + @param Map Boundary. - @retval EFI_SUCCESS Successfully returned. + @retval EFI_SUCCESS Successfully returned. @retval EFI_UNSUPPORTED These adjacent regions could not merge. **/ -STATIC EFI_STATUS CoreMergeGcdMapEntry ( IN LIST_ENTRY *Link, @@ -376,16 +540,15 @@ CoreMergeGcdMapEntry ( /** Merge adjacent entries on total chain. - @param TopEntry Top entry of GCD map. - @param BottomEntry Bottom entry of GCD map. - @param StartLink Start link of the list for this loop. - @param EndLink End link of the list for this loop. - @param Map Boundary. + @param TopEntry Top entry of GCD map. + @param BottomEntry Bottom entry of GCD map. + @param StartLink Start link of the list for this loop. + @param EndLink End link of the list for this loop. + @param Map Boundary. @retval EFI_SUCCESS GCD map successfully cleaned up. **/ -STATIC EFI_STATUS CoreCleanupGcdMapEntry ( IN EFI_GCD_MAP_ENTRY *TopEntry, @@ -418,19 +581,18 @@ CoreCleanupGcdMapEntry ( /** Search a segment of memory space in GCD map. The result is a range of GCD entry list. - @param BaseAddress The start address of the segment. - @param Length The length of the segment. - @param StartLink The first GCD entry involves this segment of - memory space. - @param EndLink The first GCD entry involves this segment of - memory space. - @param Map Points to the start entry to search. + @param BaseAddress The start address of the segment. + @param Length The length of the segment. + @param StartLink The first GCD entry involves this segment of + memory space. + @param EndLink The first GCD entry involves this segment of + memory space. + @param Map Points to the start entry to search. - @retval EFI_SUCCESS Successfully found the entry. + @retval EFI_SUCCESS Successfully found the entry. @retval EFI_NOT_FOUND Not found. **/ -STATIC EFI_STATUS CoreSearchGcdMapEntry ( IN EFI_PHYSICAL_ADDRESS BaseAddress, @@ -455,7 +617,7 @@ CoreSearchGcdMapEntry ( *StartLink = Link; } if (*StartLink != NULL) { - if ((BaseAddress + Length - 1) >= Entry->BaseAddress && + if ((BaseAddress + Length - 1) >= Entry->BaseAddress && (BaseAddress + Length - 1) <= Entry->EndAddress ) { *EndLink = Link; return EFI_SUCCESS; @@ -463,6 +625,7 @@ CoreSearchGcdMapEntry ( } Link = Link->ForwardLink; } + return EFI_NOT_FOUND; } @@ -470,12 +633,11 @@ CoreSearchGcdMapEntry ( /** Count the amount of GCD map entries. - @param Map Points to the start entry to do the count loop. + @param Map Points to the start entry to do the count loop. @return The count. **/ -STATIC UINTN CoreCountGcdMapEntry ( IN LIST_ENTRY *Map @@ -490,6 +652,7 @@ CoreCountGcdMapEntry ( Count++; Link = Link->ForwardLink; } + return Count; } @@ -498,66 +661,62 @@ CoreCountGcdMapEntry ( /** Return the memory attribute specified by Attributes - @param Attributes A num with some attribute bits on. + @param Attributes A num with some attribute bits on. @return The enum value of memory attribute. **/ -STATIC UINT64 ConverToCpuArchAttributes ( UINT64 Attributes - ) + ) { - if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) { - return EFI_MEMORY_UC; - } - - if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) { - return EFI_MEMORY_WC; - } + UINT64 CpuArchAttributes; - 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; + CpuArchAttributes = Attributes & NONEXCLUSIVE_MEMORY_ATTRIBUTES; + if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) { + CpuArchAttributes |= EFI_MEMORY_UC; + } else if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) { + CpuArchAttributes |= EFI_MEMORY_WC; + } else if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) { + CpuArchAttributes |= EFI_MEMORY_WT; + } else if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) { + CpuArchAttributes |= EFI_MEMORY_WB; + } else if ( (Attributes & EFI_MEMORY_UCE) == EFI_MEMORY_UCE) { + CpuArchAttributes |= EFI_MEMORY_UCE; + } else if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) { + CpuArchAttributes |= EFI_MEMORY_WP; + } + + return CpuArchAttributes; } /** Do operation on a segment of memory space specified (add, free, remove, change attribute ...). - @param Operation The type of the operation - @param GcdMemoryType Additional information for the operation - @param GcdIoType Additional information for the operation - @param BaseAddress Start address of the segment - @param Length length of the segment - @param Capabilities The alterable attributes of a newly added entry - @param Attributes The attributes needs to be set - - @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when - setting attribute. - @retval EFI_SUCCESS Action successfully done. - @retval EFI_UNSUPPORTED Could not find the proper descriptor on this - segment or set an upsupported attribute. - @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an - image. - @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist - space, and so on. + @param Operation The type of the operation + @param GcdMemoryType Additional information for the operation + @param GcdIoType Additional information for the operation + @param BaseAddress Start address of the segment + @param Length length of the segment + @param Capabilities The alterable attributes of a newly added entry + @param Attributes The attributes needs to be set + + @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when + setting attribute. + @retval EFI_SUCCESS Action successfully done. + @retval EFI_UNSUPPORTED Could not find the proper descriptor on this + segment or set an upsupported attribute. + @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an + image. + @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist + space, and so on. @retval EFI_OUT_OF_RESOURCES No buffer could be allocated. - + @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol + is not available yet. **/ -STATIC EFI_STATUS CoreConvertSpace ( IN UINTN Operation, @@ -577,11 +736,10 @@ CoreConvertSpace ( EFI_GCD_MAP_ENTRY *BottomEntry; LIST_ENTRY *StartLink; LIST_ENTRY *EndLink; - - EFI_CPU_ARCH_PROTOCOL *CpuArch; - UINT64 CpuArchAttributes; + UINT64 CpuArchAttributes; if (Length == 0) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } @@ -589,10 +747,11 @@ CoreConvertSpace ( if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) { CoreAcquireGcdMemoryLock (); Map = &mGcdMemorySpaceMap; - } - if ((Operation & GCD_IO_SPACE_OPERATION) != 0) { + } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) { CoreAcquireGcdIoLock (); Map = &mGcdIoSpaceMap; + } else { + ASSERT (FALSE); } // @@ -604,6 +763,7 @@ CoreConvertSpace ( goto Done; } + ASSERT (StartLink != NULL && EndLink != NULL); // // Verify that the list of descriptors are unallocated non-existent memory. @@ -663,13 +823,12 @@ CoreConvertSpace ( } break; // - // Set attribute operations + // Set attributes operation // case GCD_SET_ATTRIBUTES_MEMORY_OPERATION: if ((Attributes & EFI_MEMORY_RUNTIME) != 0) { if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) { Status = EFI_INVALID_PARAMETER; - goto Done; } } @@ -678,6 +837,23 @@ CoreConvertSpace ( goto Done; } break; + // + // Set capabilities operation + // + case GCD_SET_CAPABILITIES_MEMORY_OPERATION: + if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) { + Status = EFI_INVALID_PARAMETER; + + goto Done; + } + // + // Current attributes must still be supported with new capabilities + // + if ((Capabilities & Entry->Attributes) != Entry->Attributes) { + Status = EFI_UNSUPPORTED; + goto Done; + } + break; } Link = Link->ForwardLink; } @@ -690,33 +866,30 @@ CoreConvertSpace ( Status = EFI_OUT_OF_RESOURCES; goto Done; } + ASSERT (TopEntry != NULL && BottomEntry != NULL); - // - // - // 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 = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch); - if (EFI_ERROR (Status)) { - Status = EFI_ACCESS_DENIED; - goto Done; + if (CpuArchAttributes != INVALID_CPU_ARCH_ATTRIBUTES) { + if (gCpu == NULL) { + Status = EFI_NOT_AVAILABLE_YET; + } else { + Status = gCpu->SetMemoryAttributes ( + gCpu, + BaseAddress, + Length, + CpuArchAttributes + ); } - - Status = CpuArch->SetMemoryAttributes ( - CpuArch, - BaseAddress, - Length, - CpuArchAttributes - ); if (EFI_ERROR (Status)) { + CoreFreePool (TopEntry); + CoreFreePool (BottomEntry); goto Done; } } - } // @@ -760,11 +933,17 @@ CoreConvertSpace ( Entry->GcdIoType = EfiGcdIoTypeNonExistent; break; // - // Set attribute operations + // Set attributes operation // case GCD_SET_ATTRIBUTES_MEMORY_OPERATION: Entry->Attributes = Attributes; break; + // + // Set capabilities operation + // + case GCD_SET_CAPABILITIES_MEMORY_OPERATION: + Entry->Capabilities = Capabilities; + break; } Link = Link->ForwardLink; } @@ -775,11 +954,15 @@ CoreConvertSpace ( Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map); Done: + DEBUG ((DEBUG_GCD, " Status = %r\n", Status)); + if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) { CoreReleaseGcdMemoryLock (); + CoreDumpGcdMemorySpaceMap (FALSE); } if ((Operation & GCD_IO_SPACE_OPERATION) != 0) { CoreReleaseGcdIoLock (); + CoreDumpGcdIoSpaceMap (FALSE); } return Status; @@ -789,19 +972,18 @@ Done: /** Check whether an entry could be used to allocate space. - @param Operation Allocate memory or IO - @param Entry The entry to be tested - @param GcdMemoryType The desired memory type - @param GcdIoType The desired IO type + @param Operation Allocate memory or IO + @param Entry The entry to be tested + @param GcdMemoryType The desired memory type + @param GcdIoType The desired IO type - @retval EFI_NOT_FOUND The memory type does not match or there's an - image handle on the entry. - @retval EFI_UNSUPPORTED The operation unsupported. - @retval EFI_SUCCESS It's ok for this entry to be used to allocate + @retval EFI_NOT_FOUND The memory type does not match or there's an + image handle on the entry. + @retval EFI_UNSUPPORTED The operation unsupported. + @retval EFI_SUCCESS It's ok for this entry to be used to allocate space. **/ -STATIC EFI_STATUS CoreAllocateSpaceCheckEntry ( IN UINTN Operation, @@ -834,22 +1016,21 @@ CoreAllocateSpaceCheckEntry ( /** Allocate space on specified address and length. - @param Operation The type of operation (memory or IO) - @param GcdAllocateType The type of allocate operation - @param GcdMemoryType The desired memory type - @param GcdIoType The desired IO type - @param Alignment Align with 2^Alignment - @param Length Length to allocate - @param BaseAddress Base address to allocate - @param ImageHandle The image handle consume the allocated space. - @param DeviceHandle The device handle consume the allocated space. - - @retval EFI_INVALID_PARAMETER Invalid parameter. - @retval EFI_NOT_FOUND No descriptor for the desired space exists. + @param Operation The type of operation (memory or IO) + @param GcdAllocateType The type of allocate operation + @param GcdMemoryType The desired memory type + @param GcdIoType The desired IO type + @param Alignment Align with 2^Alignment + @param Length Length to allocate + @param BaseAddress Base address to allocate + @param ImageHandle The image handle consume the allocated space. + @param DeviceHandle The device handle consume the allocated space. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_NOT_FOUND No descriptor for the desired space exists. @retval EFI_SUCCESS Space successfully allocated. **/ -STATIC EFI_STATUS CoreAllocateSpace ( IN UINTN Operation, @@ -879,25 +1060,32 @@ CoreAllocateSpace ( // // Make sure parameters are valid // - if (GcdAllocateType < 0 || GcdAllocateType >= EfiGcdMaxAllocateType) { + if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } - if (GcdMemoryType < 0 || GcdMemoryType >= EfiGcdMemoryTypeMaximum) { + if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } - if (GcdIoType < 0 || GcdIoType >= EfiGcdIoTypeMaximum) { + if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } if (BaseAddress == NULL) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } if (ImageHandle == NULL) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } if (Alignment >= 64) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_NOT_FOUND)); return EFI_NOT_FOUND; } if (Length == 0) { + DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER)); return EFI_INVALID_PARAMETER; } @@ -905,10 +1093,11 @@ CoreAllocateSpace ( if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) { CoreAcquireGcdMemoryLock (); Map = &mGcdMemorySpaceMap; - } - if ((Operation & GCD_IO_SPACE_OPERATION) != 0) { + } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) { CoreAcquireGcdIoLock (); Map = &mGcdIoSpaceMap; + } else { + ASSERT (FALSE); } Found = FALSE; @@ -936,6 +1125,7 @@ CoreAllocateSpace ( Status = EFI_NOT_FOUND; goto Done; } + ASSERT (StartLink != NULL && EndLink != NULL); // // Verify that the list of descriptors are unallocated memory matching GcdMemoryType. @@ -989,7 +1179,7 @@ CoreAllocateSpace ( } if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown || - GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) { + GcdAllocateType == EfiGcdAllocateAnySearchTopDown) { if ((Entry->BaseAddress + Length) > MaxAddress) { continue; } @@ -1019,6 +1209,7 @@ CoreAllocateSpace ( Status = EFI_NOT_FOUND; goto Done; } + ASSERT (StartLink != NULL && EndLink != NULL); Link = StartLink; // @@ -1054,6 +1245,7 @@ CoreAllocateSpace ( Status = EFI_OUT_OF_RESOURCES; goto Done; } + ASSERT (TopEntry != NULL && BottomEntry != NULL); // // Convert/Insert the list of descriptors from StartLink to EndLink @@ -1073,11 +1265,19 @@ CoreAllocateSpace ( Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map); Done: + DEBUG ((DEBUG_GCD, " Status = %r", Status)); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_GCD, " (BaseAddress = %016lx)", *BaseAddress)); + } + DEBUG ((DEBUG_GCD, "\n")); + if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) { CoreReleaseGcdMemoryLock (); + CoreDumpGcdMemorySpaceMap (FALSE); } if ((Operation & GCD_IO_SPACE_OPERATION) !=0) { CoreReleaseGcdIoLock (); + CoreDumpGcdIoSpaceMap (FALSE); } return Status; @@ -1087,16 +1287,15 @@ Done: /** Add a segment of memory to GCD map. - @param GcdMemoryType Memory type of the segment. - @param BaseAddress Base address of the segment. - @param Length Length of the segment. - @param Capabilities alterable attributes of the segment. + @param GcdMemoryType Memory type of the segment. + @param BaseAddress Base address of the segment. + @param Length Length of the segment. + @param Capabilities alterable attributes of the segment. - @retval EFI_INVALID_PARAMETER Invalid parameters. + @retval EFI_INVALID_PARAMETER Invalid parameters. @retval EFI_SUCCESS Successfully add a segment of memory space. **/ -STATIC EFI_STATUS CoreInternalAddMemorySpace ( IN EFI_GCD_MEMORY_TYPE GcdMemoryType, @@ -1105,6 +1304,10 @@ CoreInternalAddMemorySpace ( IN UINT64 Capabilities ) { + DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)])); + DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities)); + // // Make sure parameters are valid // @@ -1123,20 +1326,21 @@ CoreInternalAddMemorySpace ( Allocates nonexistent memory, reserved memory, system memory, or memorymapped I/O resources from the global coherency domain of the processor. - @param GcdAllocateType The type of allocate operation - @param GcdMemoryType The desired memory type - @param Alignment Align with 2^Alignment - @param Length Length to allocate - @param BaseAddress Base address to allocate - @param ImageHandle The image handle consume the allocated space. - @param DeviceHandle The device handle consume the allocated space. + @param GcdAllocateType The type of allocate operation + @param GcdMemoryType The desired memory type + @param Alignment Align with 2^Alignment + @param Length Length to allocate + @param BaseAddress Base address to allocate + @param ImageHandle The image handle consume the allocated space. + @param DeviceHandle The device handle consume the allocated space. - @retval EFI_INVALID_PARAMETER Invalid parameter. - @retval EFI_NOT_FOUND No descriptor contains the desired space. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_NOT_FOUND No descriptor contains the desired space. @retval EFI_SUCCESS Memory space successfully allocated. **/ EFI_STATUS +EFIAPI CoreAllocateMemorySpace ( IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, IN EFI_GCD_MEMORY_TYPE GcdMemoryType, @@ -1147,15 +1351,26 @@ CoreAllocateMemorySpace ( IN EFI_HANDLE DeviceHandle OPTIONAL ) { + if (BaseAddress != NULL) { + DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length)); + } else { + DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=,Length=%016lx)\n", Length)); + } + DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)])); + DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)])); + DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment))); + DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle)); + DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle)); + return CoreAllocateSpace ( - GCD_ALLOCATE_MEMORY_OPERATION, - GcdAllocateType, - GcdMemoryType, - (EFI_GCD_IO_TYPE) 0, - Alignment, - Length, - BaseAddress, - ImageHandle, + GCD_ALLOCATE_MEMORY_OPERATION, + GcdAllocateType, + GcdMemoryType, + (EFI_GCD_IO_TYPE) 0, + Alignment, + Length, + BaseAddress, + ImageHandle, DeviceHandle ); } @@ -1165,15 +1380,16 @@ CoreAllocateMemorySpace ( Adds reserved memory, system memory, or memory-mapped I/O resources to the global coherency domain of the processor. - @param GcdMemoryType Memory type of the memory space. - @param BaseAddress Base address of the memory space. - @param Length Length of the memory space. - @param Capabilities alterable attributes of the memory space. + @param GcdMemoryType Memory type of the memory space. + @param BaseAddress Base address of the memory space. + @param Length Length of the memory space. + @param Capabilities alterable attributes of the memory space. @retval EFI_SUCCESS Merged this memory space into GCD map. **/ EFI_STATUS +EFIAPI CoreAddMemorySpace ( IN EFI_GCD_MEMORY_TYPE GcdMemoryType, IN EFI_PHYSICAL_ADDRESS BaseAddress, @@ -1187,15 +1403,15 @@ CoreAddMemorySpace ( Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities); - if (!EFI_ERROR (Status) && GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) { - PageBaseAddress = PageAlignLength (BaseAddress); + PageBaseAddress = PageAlignAddress (BaseAddress); PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress); Status = CoreAllocateMemorySpace ( EfiGcdAllocateAddress, GcdMemoryType, - EFI_PAGE_SHIFT, + EFI_PAGE_SHIFT, PageLength, &PageBaseAddress, gDxeCoreImageHandle, @@ -1214,7 +1430,7 @@ CoreAddMemorySpace ( Status = CoreAllocateMemorySpace ( EfiGcdAllocateAddress, GcdMemoryType, - EFI_PAGE_SHIFT, + EFI_PAGE_SHIFT, EFI_PAGE_SIZE, &PageBaseAddress, gDxeCoreImageHandle, @@ -1240,18 +1456,21 @@ CoreAddMemorySpace ( Frees nonexistent memory, reserved memory, system memory, or memory-mapped I/O resources from the global coherency domain of the processor. - @param BaseAddress Base address of the memory space. - @param Length Length of the memory space. + @param BaseAddress Base address of the memory space. + @param Length Length of the memory space. @retval EFI_SUCCESS Space successfully freed. **/ EFI_STATUS +EFIAPI CoreFreeMemorySpace ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length ) { + DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0); } @@ -1260,18 +1479,21 @@ CoreFreeMemorySpace ( Removes reserved memory, system memory, or memory-mapped I/O resources from the global coherency domain of the processor. - @param BaseAddress Base address of the memory space. - @param Length Length of the memory space. + @param BaseAddress Base address of the memory space. + @param Length Length of the memory space. @retval EFI_SUCCESS Successfully remove a segment of memory space. **/ EFI_STATUS +EFIAPI CoreRemoveMemorySpace ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length ) { + DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0); } @@ -1279,11 +1501,10 @@ CoreRemoveMemorySpace ( /** Build a memory descriptor according to an entry. - @param Descriptor The descriptor to be built + @param Descriptor The descriptor to be built @param Entry According to this entry **/ -STATIC VOID BuildMemoryDescriptor ( IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor, @@ -1303,14 +1524,15 @@ BuildMemoryDescriptor ( /** Retrieves the descriptor for a memory region containing a specified address. - @param BaseAddress Specified start address - @param Descriptor Specified length + @param BaseAddress Specified start address + @param Descriptor Specified length - @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_INVALID_PARAMETER Invalid parameter @retval EFI_SUCCESS Successfully get memory space descriptor. **/ EFI_STATUS +EFIAPI CoreGetMemorySpaceDescriptor ( IN EFI_PHYSICAL_ADDRESS BaseAddress, OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor @@ -1331,12 +1553,13 @@ CoreGetMemorySpaceDescriptor ( CoreAcquireGcdMemoryLock (); // - // Search for the list of descriptors that contain BaseAddress + // Search for the list of descriptors that contain BaseAddress // Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap); if (EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; } else { + ASSERT (StartLink != NULL && EndLink != NULL); // // Copy the contents of the found descriptor into Descriptor // @@ -1354,38 +1577,92 @@ CoreGetMemorySpaceDescriptor ( Modifies the attributes for a memory region in the global coherency domain of the processor. - @param BaseAddress Specified start address - @param Length Specified length - @param Attributes Specified attributes - - @retval EFI_SUCCESS Successfully set attribute of a segment of - memory space. + @param BaseAddress Specified start address + @param Length Specified length + @param Attributes Specified attributes + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is + not available yet. **/ EFI_STATUS +EFIAPI CoreSetMemorySpaceAttributes ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes ) { + DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + DEBUG ((DEBUG_GCD, " Attributes = %016lx\n", Attributes)); + return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes); } +/** + Modifies the capabilities for a memory region in the global coherency domain of the + processor. + + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Capabilities The bit mask of capabilities that the memory region supports. + + @retval EFI_SUCCESS The capabilities were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the + memory region attributes currently in use. + @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities + of the memory resource range. +**/ +EFI_STATUS +EFIAPI +CoreSetMemorySpaceCapabilities ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities)); + + Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0); + if (!EFI_ERROR(Status)) { + CoreUpdateMemoryAttributes(BaseAddress, RShiftU64(Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME)); + } + + return Status; +} + + /** Returns a map of the memory resources in the global coherency domain of the processor. - @param NumberOfDescriptors Number of descriptors. - @param MemorySpaceMap Descriptor array + @param NumberOfDescriptors Number of descriptors. + @param MemorySpaceMap Descriptor array - @retval EFI_INVALID_PARAMETER Invalid parameter - @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate @retval EFI_SUCCESS Successfully get memory space map. **/ EFI_STATUS +EFIAPI CoreGetMemorySpaceMap ( OUT UINTN *NumberOfDescriptors, OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap @@ -1416,7 +1693,7 @@ CoreGetMemorySpaceMap ( // // Allocate the MemorySpaceMap // - *MemorySpaceMap = CoreAllocateBootServicesPool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)); + *MemorySpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)); if (*MemorySpaceMap == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; @@ -1444,21 +1721,25 @@ Done: /** Adds reserved I/O or I/O resources to the global coherency domain of the processor. - @param GcdIoType IO type of the segment. - @param BaseAddress Base address of the segment. - @param Length Length of the segment. + @param GcdIoType IO type of the segment. + @param BaseAddress Base address of the segment. + @param Length Length of the segment. - @retval EFI_SUCCESS Merged this segment into GCD map. + @retval EFI_SUCCESS Merged this segment into GCD map. @retval EFI_INVALID_PARAMETER Parameter not valid **/ EFI_STATUS +EFIAPI CoreAddIoSpace ( IN EFI_GCD_IO_TYPE GcdIoType, IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length ) { + DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)])); + // // Make sure parameters are valid // @@ -1473,20 +1754,21 @@ CoreAddIoSpace ( Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency domain of the processor. - @param GcdAllocateType The type of allocate operation - @param GcdIoType The desired IO type - @param Alignment Align with 2^Alignment - @param Length Length to allocate - @param BaseAddress Base address to allocate - @param ImageHandle The image handle consume the allocated space. - @param DeviceHandle The device handle consume the allocated space. + @param GcdAllocateType The type of allocate operation + @param GcdIoType The desired IO type + @param Alignment Align with 2^Alignment + @param Length Length to allocate + @param BaseAddress Base address to allocate + @param ImageHandle The image handle consume the allocated space. + @param DeviceHandle The device handle consume the allocated space. - @retval EFI_INVALID_PARAMETER Invalid parameter. - @retval EFI_NOT_FOUND No descriptor contains the desired space. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_NOT_FOUND No descriptor contains the desired space. @retval EFI_SUCCESS IO space successfully allocated. **/ EFI_STATUS +EFIAPI CoreAllocateIoSpace ( IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, IN EFI_GCD_IO_TYPE GcdIoType, @@ -1497,15 +1779,26 @@ CoreAllocateIoSpace ( IN EFI_HANDLE DeviceHandle OPTIONAL ) { + if (BaseAddress != NULL) { + DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length)); + } else { + DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=,Length=%016lx)\n", Length)); + } + DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)])); + DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)])); + DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment))); + DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle)); + DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle)); + return CoreAllocateSpace ( - GCD_ALLOCATE_IO_OPERATION, - GcdAllocateType, - (EFI_GCD_MEMORY_TYPE) 0, - GcdIoType, - Alignment, - Length, - BaseAddress, - ImageHandle, + GCD_ALLOCATE_IO_OPERATION, + GcdAllocateType, + (EFI_GCD_MEMORY_TYPE) 0, + GcdIoType, + Alignment, + Length, + BaseAddress, + ImageHandle, DeviceHandle ); } @@ -1515,18 +1808,21 @@ CoreAllocateIoSpace ( Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency domain of the processor. - @param BaseAddress Base address of the segment. - @param Length Length of the segment. + @param BaseAddress Base address of the segment. + @param Length Length of the segment. @retval EFI_SUCCESS Space successfully freed. **/ EFI_STATUS +EFIAPI CoreFreeIoSpace ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length ) { + DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0); } @@ -1535,18 +1831,21 @@ CoreFreeIoSpace ( Removes reserved I/O or I/O resources from the global coherency domain of the processor. - @param BaseAddress Base address of the segment. - @param Length Length of the segment. + @param BaseAddress Base address of the segment. + @param Length Length of the segment. @retval EFI_SUCCESS Successfully removed a segment of IO space. **/ EFI_STATUS +EFIAPI CoreRemoveIoSpace ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length ) { + DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length)); + return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0); } @@ -1554,11 +1853,10 @@ CoreRemoveIoSpace ( /** Build a IO descriptor according to an entry. - @param Descriptor The descriptor to be built + @param Descriptor The descriptor to be built @param Entry According to this entry **/ -STATIC VOID BuildIoDescriptor ( IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor, @@ -1576,14 +1874,15 @@ BuildIoDescriptor ( /** Retrieves the descriptor for an I/O region containing a specified address. - @param BaseAddress Specified start address - @param Descriptor Specified length + @param BaseAddress Specified start address + @param Descriptor Specified length - @retval EFI_INVALID_PARAMETER Descriptor is NULL. + @retval EFI_INVALID_PARAMETER Descriptor is NULL. @retval EFI_SUCCESS Successfully get the IO space descriptor. **/ EFI_STATUS +EFIAPI CoreGetIoSpaceDescriptor ( IN EFI_PHYSICAL_ADDRESS BaseAddress, OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor @@ -1604,12 +1903,13 @@ CoreGetIoSpaceDescriptor ( CoreAcquireGcdIoLock (); // - // Search for the list of descriptors that contain BaseAddress + // Search for the list of descriptors that contain BaseAddress // Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap); if (EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; } else { + ASSERT (StartLink != NULL && EndLink != NULL); // // Copy the contents of the found descriptor into Descriptor // @@ -1626,15 +1926,16 @@ CoreGetIoSpaceDescriptor ( /** Returns a map of the I/O resources in the global coherency domain of the processor. - @param NumberOfDescriptors Number of descriptors. - @param IoSpaceMap Descriptor array + @param NumberOfDescriptors Number of descriptors. + @param IoSpaceMap Descriptor array - @retval EFI_INVALID_PARAMETER Invalid parameter - @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate @retval EFI_SUCCESS Successfully get IO space map. **/ EFI_STATUS +EFIAPI CoreGetIoSpaceMap ( OUT UINTN *NumberOfDescriptors, OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap @@ -1665,7 +1966,7 @@ CoreGetIoSpaceMap ( // // Allocate the IoSpaceMap // - *IoSpaceMap = CoreAllocateBootServicesPool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR)); + *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR)); if (*IoSpaceMap == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; @@ -1687,21 +1988,20 @@ CoreGetIoSpaceMap ( Done: CoreReleaseGcdIoLock (); return Status; -} +} /** Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor capabilities mask - @param GcdMemoryType Type of resource in the GCD memory map. - @param Attributes The attribute mask in the Resource Descriptor - HOB. + @param GcdMemoryType Type of resource in the GCD memory map. + @param Attributes The attribute mask in the Resource Descriptor + HOB. @return The capabilities mask for an EFI Memory Descriptor. **/ -STATIC UINT64 CoreConvertResourceDescriptorHobAttributesToCapabilities ( EFI_GCD_MEMORY_TYPE GcdMemoryType, @@ -1710,34 +2010,57 @@ CoreConvertResourceDescriptorHobAttributesToCapabilities ( { UINT64 Capabilities; GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion; - + // // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask // for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) { - if (Conversion->Memory || (GcdMemoryType != EfiGcdMemoryTypeSystemMemory)) { + if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) { if (Attributes & Conversion->Attribute) { Capabilities |= Conversion->Capability; } } } - + return Capabilities; } +/** + Calculate total memory bin size neeeded. + + @return The total memory bin size neeeded. + +**/ +UINT64 +CalculateTotalMemoryBinSizeNeeded ( + VOID + ) +{ + UINTN Index; + UINT64 TotalSize; + + // + // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array + // + TotalSize = 0; + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT); + } + + return TotalSize; +} /** - External function. Initializes the GCD and memory services based on the memory - descriptor HOBs. This function is responsible for priming the GCD map and the - memory map, so memory allocations and resource allocations can be made. The first - part of this function can not depend on any memory services until at least one - memory descriptor is provided to the memory services. Then the memory services - can be used to intialize the GCD map. + External function. Initializes memory services based on the memory + descriptor HOBs. This function is responsible for priming the memory + map, so memory allocations and resource allocations can be made. + The first part of this function can not depend on any memory services + until at least one memory descriptor is provided to the memory services. - @param HobStart The start address of the HOB. - @param MemoryBaseAddress Start address of memory region found to init DXE - core. - @param MemoryLength Length of memory region found to init DXE core. + @param HobStart The start address of the HOB. + @param MemoryBaseAddress Start address of memory region found to init DXE + core. + @param MemoryLength Length of memory region found to init DXE core. @retval EFI_SUCCESS Memory services successfully initialized. @@ -1760,13 +2083,12 @@ CoreInitializeMemoryServices ( UINT64 Length; UINT64 Attributes; UINT64 Capabilities; - EFI_PHYSICAL_ADDRESS MaxMemoryBaseAddress; - UINT64 MaxMemoryLength; - UINT64 MaxMemoryAttributes; - EFI_PHYSICAL_ADDRESS MaxAddress; + EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress; + UINT64 TestedMemoryLength; EFI_PHYSICAL_ADDRESS HighAddress; - EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob; EFI_HOB_GUID_TYPE *GuidHob; + UINT32 ReservedCodePageNumber; + UINT64 MinimalMemorySizeNeeded; // // Point at the first HOB. This must be the PHIT HOB. @@ -1784,20 +2106,26 @@ CoreInitializeMemoryServices ( // Initialize Local Variables // PhitResourceHob = NULL; - MaxResourceHob = NULL; ResourceHob = NULL; BaseAddress = 0; Length = 0; Attributes = 0; - MaxMemoryBaseAddress = 0; - MaxMemoryLength = 0; - MaxMemoryAttributes = 0; // // Cache the PHIT HOB for later use // PhitHob = Hob.HandoffInformationTable; - + + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { + ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber); + ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber); + + // + // cache the Top address for loading modules at Fixed Address + // + gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop + + EFI_PAGES_TO_SIZE(ReservedCodePageNumber); + } // // See if a Memory Type Information HOB is available // @@ -1811,43 +2139,72 @@ CoreInitializeMemoryServices ( } // - // Find the Resource Descriptor HOB that contains range FreeMemoryBaseAddress..FreeMemoryLength + // Include the total memory bin size needed to make sure memory bin could be allocated successfully. + // + MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded (); + + // + // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop // - Length = 0; Found = FALSE; for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } - if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { - - ResourceHob = Hob.ResourceDescriptor; + // + // Skip Resource Descriptor HOBs that do not describe tested system memory + // + ResourceHob = Hob.ResourceDescriptor; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } - if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && - (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES ) { + // + // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop + // + if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) { + continue; + } + if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) { + continue; + } - if (PhitHob->EfiFreeMemoryBottom >= ResourceHob->PhysicalStart && - PhitHob->EfiFreeMemoryTop <= (ResourceHob->PhysicalStart + ResourceHob->ResourceLength) ) { + // + // Cache the resource descriptor HOB for the memory region described by the PHIT HOB + // + PhitResourceHob = ResourceHob; + Found = TRUE; - // - // Cache the resource descriptor HOB for the memory region described by the PHIT HOB - // - PhitResourceHob = ResourceHob; - Found = TRUE; - - Attributes = PhitResourceHob->ResourceAttribute; - BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop); - Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress); - if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { - BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom); - Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress); - if (Length < MINIMUM_INITIAL_MEMORY_SIZE) { - BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart); - Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress)); - } - } - break; - } + // + // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB + // + Attributes = PhitResourceHob->ResourceAttribute; + BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop); + Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress); + if (Length < MinimalMemorySizeNeeded) { + // + // If that range is not large enough to intialize the DXE Core, then + // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop + // + BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom); + Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress); + if (Length < MinimalMemorySizeNeeded) { + // + // If that range is not large enough to intialize the DXE Core, then + // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List + // + BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart); + Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress)); } } + break; } // @@ -1856,75 +2213,88 @@ CoreInitializeMemoryServices ( ASSERT (Found); // - // Search all the resource descriptor HOBs from the highest possible addresses down for a memory - // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB. - // The max address must be within the physically addressible range for the processor. + // Take the range in the resource descriptor HOB for the memory region described + // by the PHIT as higher priority if it is big enough. It can make the memory bin + // allocated to be at the same memory region with PHIT that has more better compatibility + // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory. // - MaxMemoryLength = 0; - MaxAddress = EFI_MAX_ADDRESS; - do { - HighAddress = 0; - Found = FALSE; + if (Length < MinimalMemorySizeNeeded) { // - // Search for a tested memory region that is below MaxAddress + // Search all the resource descriptor HOBs from the highest possible addresses down for a memory + // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB. + // The max address must be within the physically addressible range for the processor. // + HighAddress = MAX_ADDRESS; for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { - // - // See if this is a resource descriptor HOB that does not contain the PHIT. + // Skip the Resource Descriptor HOB that contains the PHIT + // + if (Hob.ResourceDescriptor == PhitResourceHob) { + continue; + } + // + // Skip all HOBs except Resource Descriptor HOBs // - if (Hob.ResourceDescriptor != PhitResourceHob && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } - ResourceHob = Hob.ResourceDescriptor; - // - // See if this resource descrior HOB describes tested system memory below MaxAddress - // - if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && - (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES && - ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MaxAddress ) { + // + // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ADDRESS + // + ResourceHob = Hob.ResourceDescriptor; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } + if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS) { + continue; + } - // - // See if this is the highest tested system memory region below MaxAddress - // - if (ResourceHob->PhysicalStart > HighAddress) { + // + // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB + // + if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) { + continue; + } - MaxResourceHob = ResourceHob; - HighAddress = MaxResourceHob->PhysicalStart; - Found = TRUE; - } - } + // + // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core + // + TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart); + TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress); + if (TestedMemoryLength < MinimalMemorySizeNeeded) { + continue; } - } - if (Found) { + // - // Compute the size of the tested memory region below MaxAddrees + // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core // - MaxMemoryBaseAddress = PageAlignAddress (MaxResourceHob->PhysicalStart); - MaxMemoryLength = PageAlignLength (MaxResourceHob->PhysicalStart + MaxResourceHob->ResourceLength - MaxMemoryBaseAddress); - MaxMemoryAttributes = MaxResourceHob->ResourceAttribute; + BaseAddress = TestedMemoryBaseAddress; + Length = TestedMemoryLength; + Attributes = ResourceHob->ResourceAttribute; + HighAddress = ResourceHob->PhysicalStart; } - MaxAddress = ResourceHob->PhysicalStart; - } while (Found && MaxMemoryLength < MINIMUM_INITIAL_MEMORY_SIZE); - - // - // - // - if ((Length < MINIMUM_INITIAL_MEMORY_SIZE) || - (MaxMemoryBaseAddress > BaseAddress && MaxMemoryLength >= MINIMUM_INITIAL_MEMORY_SIZE) ) { - BaseAddress = MaxMemoryBaseAddress; - Length = MaxMemoryLength; - Attributes = MaxMemoryAttributes; } + DEBUG ((EFI_D_INFO, "CoreInitializeMemoryServices:\n")); + DEBUG ((EFI_D_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded)); + // // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT(). // - ASSERT (Length >= MINIMUM_INITIAL_MEMORY_SIZE); + ASSERT (Length >= MinimalMemorySizeNeeded); // // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask // - Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes); + if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) { + Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes); + } else { + Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes); + } // // Declare the very first memory region, so the EFI Memory Services are available. @@ -1946,30 +2316,27 @@ CoreInitializeMemoryServices ( /** External function. Initializes the GCD and memory services based on the memory descriptor HOBs. This function is responsible for priming the GCD map and the - memory map, so memory allocations and resource allocations can be made. The first - part of this function can not depend on any memory services until at least one - memory descriptor is provided to the memory services. Then the memory services - can be used to intialize the GCD map. The HobStart will be relocated to a pool - buffer. + memory map, so memory allocations and resource allocations can be made. The + HobStart will be relocated to a pool buffer. - @param HobStart The start address of the HOB - @param MemoryBaseAddress Start address of memory region found to init DXE - core. - @param MemoryLength Length of memory region found to init DXE core. + @param HobStart The start address of the HOB + @param MemoryBaseAddress Start address of memory region found to init DXE + core. + @param MemoryLength Length of memory region found to init DXE core. @retval EFI_SUCCESS GCD services successfully initialized. **/ EFI_STATUS CoreInitializeGcdServices ( - IN OUT VOID **HobStart, + IN OUT VOID **HobStart, IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress, IN UINT64 MemoryLength ) { - EFI_PEI_HOB_POINTERS Hob; + EFI_PEI_HOB_POINTERS Hob; VOID *NewHobList; - EFI_HOB_HANDOFF_INFO_TABLE *PhitHob; + EFI_HOB_HANDOFF_INFO_TABLE *PhitHob; UINT8 SizeOfMemorySpace; UINT8 SizeOfIoSpace; EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; @@ -1987,6 +2354,8 @@ CoreInitializeGcdServices ( UINTN Index; UINT64 Capabilities; EFI_HOB_CPU * CpuHob; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList; + // // Cache the PHIT HOB for later use // @@ -1999,29 +2368,33 @@ CoreInitializeGcdServices ( ASSERT (CpuHob != NULL); SizeOfMemorySpace = CpuHob->SizeOfMemorySpace; SizeOfIoSpace = CpuHob->SizeOfIoSpace; - + // // Initialize the GCD Memory Space Map // - Entry = CoreAllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate); + Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate); ASSERT (Entry != NULL); Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1; InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link); + CoreDumpGcdMemorySpaceMap (TRUE); + // // Initialize the GCD I/O Space Map // - Entry = CoreAllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate); + Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate); ASSERT (Entry != NULL); Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1; InsertHeadList (&mGcdIoSpaceMap, &Entry->Link); + CoreDumpGcdIoSpaceMap (TRUE); + // - // Walk the HOB list and add all resource descriptors to the GCD + // Walk the HOB list and add all resource descriptors to the GCD // for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { @@ -2035,7 +2408,11 @@ CoreInitializeGcdServices ( switch (ResourceHob->ResourceType) { case EFI_RESOURCE_SYSTEM_MEMORY: if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) { - GcdMemoryType = EfiGcdMemoryTypeSystemMemory; + if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) { + GcdMemoryType = EfiGcdMemoryTypeMoreReliable; + } else { + GcdMemoryType = EfiGcdMemoryTypeSystemMemory; + } } if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) { GcdMemoryType = EfiGcdMemoryTypeReserved; @@ -2043,6 +2420,9 @@ CoreInitializeGcdServices ( if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) { GcdMemoryType = EfiGcdMemoryTypeReserved; } + if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) { + GcdMemoryType = EfiGcdMemoryTypePersistent; + } break; case EFI_RESOURCE_MEMORY_MAPPED_IO: case EFI_RESOURCE_FIRMWARE_DEVICE: @@ -2061,6 +2441,10 @@ CoreInitializeGcdServices ( } if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) { + // + // Validate the Resource HOB Attributes + // + CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute); // // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask @@ -2091,15 +2475,20 @@ CoreInitializeGcdServices ( // // Allocate first memory region from the GCD by the DXE core // - Status = CoreAllocateMemorySpace ( - EfiGcdAllocateAddress, - EfiGcdMemoryTypeSystemMemory, - 0, - MemoryLength, - &MemoryBaseAddress, - gDxeCoreImageHandle, - NULL - ); + Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor); + if (!EFI_ERROR (Status)) { + ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || + (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable)); + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + Descriptor.GcdMemoryType, + 0, + MemoryLength, + &MemoryBaseAddress, + gDxeCoreImageHandle, + NULL + ); + } // // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs, @@ -2113,14 +2502,16 @@ CoreInitializeGcdServices ( if (!EFI_ERROR (Status)) { Status = CoreAllocateMemorySpace ( EfiGcdAllocateAddress, - Descriptor.GcdMemoryType, + Descriptor.GcdMemoryType, 0, MemoryHob->AllocDescriptor.MemoryLength, &BaseAddress, gDxeCoreImageHandle, NULL ); - if (!EFI_ERROR (Status) && Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + if (!EFI_ERROR (Status) && + ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || + (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) { CoreAddMemoryDescriptor ( MemoryHob->AllocDescriptor.MemoryType, MemoryHob->AllocDescriptor.MemoryBaseAddress, @@ -2136,7 +2527,7 @@ CoreInitializeGcdServices ( BaseAddress = FirmwareVolumeHob->BaseAddress; Status = CoreAllocateMemorySpace ( EfiGcdAllocateAddress, - EfiGcdMemoryTypeMemoryMappedIo, + EfiGcdMemoryTypeMemoryMappedIo, 0, FirmwareVolumeHob->Length, &BaseAddress, @@ -2146,30 +2537,32 @@ CoreInitializeGcdServices ( } } - // - // Relocate HOB List to an allocated pool buffer. - // - NewHobList = CoreAllocateCopyPool ( - (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart), - *HobStart - ); - ASSERT (NewHobList != NULL); - - *HobStart = NewHobList; - gHobList = NewHobList; - // // Add and allocate the remaining unallocated system memory to the memory services. // Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap); + ASSERT (Status == EFI_SUCCESS); + + MemorySpaceMapHobList = NULL; for (Index = 0; Index < NumberOfDescriptors; Index++) { - if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || + (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) { if (MemorySpaceMap[Index].ImageHandle == NULL) { BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress); Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress); if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) { continue; } + if (((UINTN) MemorySpaceMap[Index].BaseAddress <= (UINTN) (*HobStart)) && + ((UINTN) (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN) PhitHob->EfiFreeMemoryBottom)) { + // + // Skip the memory space that covers HOB List, it should be processed + // after HOB List relocation to avoid the resources allocated by others + // to corrupt HOB List before its relocation. + // + MemorySpaceMapHobList = &MemorySpaceMap[Index]; + continue; + } CoreAddMemoryDescriptor ( EfiConventionalMemory, BaseAddress, @@ -2178,7 +2571,7 @@ CoreInitializeGcdServices ( ); Status = CoreAllocateMemorySpace ( EfiGcdAllocateAddress, - EfiGcdMemoryTypeSystemMemory, + MemorySpaceMap[Index].GcdMemoryType, 0, Length, &BaseAddress, @@ -2188,6 +2581,47 @@ CoreInitializeGcdServices ( } } } + + // + // Relocate HOB List to an allocated pool buffer. + // The relocation should be at after all the tested memory resources added + // (except the memory space that covers HOB List) to the memory services, + // because the memory resource found in CoreInitializeMemoryServices() + // may have not enough remaining resource for HOB List. + // + NewHobList = AllocateCopyPool ( + (UINTN) PhitHob->EfiFreeMemoryBottom - (UINTN) (*HobStart), + *HobStart + ); + ASSERT (NewHobList != NULL); + + *HobStart = NewHobList; + gHobList = NewHobList; + + if (MemorySpaceMapHobList != NULL) { + // + // Add and allocate the memory space that covers HOB List to the memory services + // after HOB List relocation. + // + BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress); + Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress); + CoreAddMemoryDescriptor ( + EfiConventionalMemory, + BaseAddress, + RShiftU64 (Length, EFI_PAGE_SHIFT), + MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME) + ); + Status = CoreAllocateMemorySpace ( + EfiGcdAllocateAddress, + MemorySpaceMapHobList->GcdMemoryType, + 0, + Length, + &BaseAddress, + gDxeCoreImageHandle, + NULL + ); + } + CoreFreePool (MemorySpaceMap); return EFI_SUCCESS;