/** Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable. **/ VOID PromoteMemoryResource ( VOID ) { LIST_ENTRY *Link; EFI_GCD_MAP_ENTRY *Entry; DEBUG ((DEBUG_PAGE, "Promote the memory resource\n")); CoreAcquireGcdMemoryLock (); Link = mGcdMemorySpaceMap.ForwardLink; while (Link != &mGcdMemorySpaceMap) { Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved && Entry->EndAddress < MAX_ADDRESS && (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) == (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) { // // Update the GCD map // Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory; Entry->Capabilities |= EFI_MEMORY_TESTED; Entry->ImageHandle = gDxeCoreImageHandle; Entry->DeviceHandle = NULL; // // Add to allocable system memory resource // CoreAddRange ( EfiConventionalMemory, Entry->BaseAddress, Entry->EndAddress, Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME) ); CoreFreeMemoryMapStack (); } Link = Link->ForwardLink; } CoreReleaseGcdMemoryLock (); return; }
/** Internal function. Converts a memory range to the specified type. The range must exist in the memory map. @param Start The first address of the range Must be page aligned @param NumberOfPages The number of pages to convert @param NewType The new type for the memory range @retval EFI_INVALID_PARAMETER Invalid parameter @retval EFI_NOT_FOUND Could not find a descriptor cover the specified range or convertion not allowed. @retval EFI_SUCCESS Successfully converts the memory range to the specified type. **/ EFI_STATUS CoreConvertPages ( IN UINT64 Start, IN UINT64 NumberOfPages, IN EFI_MEMORY_TYPE NewType ) { UINT64 NumberOfBytes; UINT64 End; UINT64 RangeEnd; UINT64 Attribute; LIST_ENTRY *Link; MEMORY_MAP *Entry; Entry = NULL; NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT); End = Start + NumberOfBytes - 1; ASSERT (NumberOfPages); ASSERT ((Start & EFI_PAGE_MASK) == 0); ASSERT (End > Start) ; ASSERT_LOCKED (&gMemoryLock); if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) { return EFI_INVALID_PARAMETER; } // // Convert the entire range // while (Start < End) { // // Find the entry that the covers the range // for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); if (Entry->Start <= Start && Entry->End > Start) { break; } } if (Link == &gMemoryMap) { DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End)); return EFI_NOT_FOUND; } // // Convert range to the end, or to the end of the descriptor // if that's all we've got // RangeEnd = End; ASSERT (Entry != NULL); if (Entry->End < End) { RangeEnd = Entry->End; } DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType)); // // Debug code - verify conversion is allowed // if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) { DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n")); return EFI_NOT_FOUND; } // // Update counters for the number of pages allocated to each memory type // if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) { if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) { if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) { mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0; } else { mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages; } } } if (NewType >= 0 && NewType < EfiMaxMemoryType) { if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) { mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages; if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) { gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages; } } } // // Pull range out of descriptor // if (Entry->Start == Start) { // // Clip start // Entry->Start = RangeEnd + 1; } else if (Entry->End == RangeEnd) { // // Clip end // Entry->End = Start - 1; } else { // // Pull it out of the center, clip current // // // Add a new one // mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE; mMapStack[mMapDepth].FromPages = FALSE; mMapStack[mMapDepth].Type = Entry->Type; mMapStack[mMapDepth].Start = RangeEnd+1; mMapStack[mMapDepth].End = Entry->End; // // Inherit Attribute from the Memory Descriptor that is being clipped // mMapStack[mMapDepth].Attribute = Entry->Attribute; Entry->End = Start - 1; ASSERT (Entry->Start < Entry->End); Entry = &mMapStack[mMapDepth]; InsertTailList (&gMemoryMap, &Entry->Link); mMapDepth += 1; ASSERT (mMapDepth < MAX_MAP_DEPTH); } // // The new range inherits the same Attribute as the Entry //it is being cut out of // Attribute = Entry->Attribute; // // If the descriptor is empty, then remove it from the map // if (Entry->Start == Entry->End + 1) { RemoveMemoryMapEntry (Entry); Entry = NULL; } // // Add our new range in // CoreAddRange (NewType, Start, RangeEnd, Attribute); // // Move any map descriptor stack to general pool // CoreFreeMemoryMapStack (); // // Bump the starting address, and convert the next range // Start = RangeEnd + 1; } // // Converted the whole range, done // return EFI_SUCCESS; }
/** Called to initialize the memory map and add descriptors to the current descriptor list. The first descriptor that is added must be general usable memory as the addition allocates heap. @param Type The type of memory to add @param Start The starting address in the memory range Must be page aligned @param NumberOfPages The number of pages in the range @param Attribute Attributes of the memory to add @return None. The range is added to the memory map **/ VOID CoreAddMemoryDescriptor ( IN EFI_MEMORY_TYPE Type, IN EFI_PHYSICAL_ADDRESS Start, IN UINT64 NumberOfPages, IN UINT64 Attribute ) { EFI_PHYSICAL_ADDRESS End; EFI_STATUS Status; UINTN Index; UINTN FreeIndex; if ((Start & EFI_PAGE_MASK) != 0) { return; } if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) { return; } CoreAcquireMemoryLock (); End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1; CoreAddRange (Type, Start, End, Attribute); CoreFreeMemoryMapStack (); CoreReleaseMemoryLock (); // // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type // if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { CoreLoadingFixedAddressHook(); } // // Check to see if the statistics for the different memory types have already been established // if (mMemoryTypeInformationInitialized) { return; } // // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array // for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { // // Make sure the memory type in the gMemoryTypeInformation[] array is valid // Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type); if (Type < 0 || Type > EfiMaxMemoryType) { continue; } if (gMemoryTypeInformation[Index].NumberOfPages != 0) { // // Allocate pages for the current memory type from the top of available memory // Status = CoreAllocatePages ( AllocateAnyPages, Type, gMemoryTypeInformation[Index].NumberOfPages, &mMemoryTypeStatistics[Type].BaseAddress ); if (EFI_ERROR (Status)) { // // If an error occurs allocating the pages for the current memory type, then // free all the pages allocates for the previous memory types and return. This // operation with be retied when/if more memory is added to the system // for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) { // // Make sure the memory type in the gMemoryTypeInformation[] array is valid // Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type); if (Type < 0 || Type > EfiMaxMemoryType) { continue; } if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) { CoreFreePages ( mMemoryTypeStatistics[Type].BaseAddress, gMemoryTypeInformation[FreeIndex].NumberOfPages ); mMemoryTypeStatistics[Type].BaseAddress = 0; mMemoryTypeStatistics[Type].MaximumAddress = MAX_ADDRESS; } } return; } // // Compute the address at the top of the current statistics // mMemoryTypeStatistics[Type].MaximumAddress = mMemoryTypeStatistics[Type].BaseAddress + LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1; // // If the current base address is the lowest address so far, then update the default // maximum address // if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) { mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1; } } } // // There was enough system memory for all the the memory types were allocated. So, // those memory areas can be freed for future allocations, and all future memory // allocations can occur within their respective bins // for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { // // Make sure the memory type in the gMemoryTypeInformation[] array is valid // Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type); if (Type < 0 || Type > EfiMaxMemoryType) { continue; } if (gMemoryTypeInformation[Index].NumberOfPages != 0) { CoreFreePages ( mMemoryTypeStatistics[Type].BaseAddress, gMemoryTypeInformation[Index].NumberOfPages ); mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages; gMemoryTypeInformation[Index].NumberOfPages = 0; } } // // If the number of pages reserved for a memory type is 0, then all allocations for that type // should be in the default range. // for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) { for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) { mMemoryTypeStatistics[Type].InformationIndex = Index; } } mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0; if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ADDRESS) { mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress; } } mMemoryTypeInformationInitialized = TRUE; }
/** Helper function of memory allocation with Guard pages. @param FreePageList The free page node. @param NumberOfPages Number of pages to be allocated. @param MaxAddress Request to allocate memory below this address. @param MemoryType Type of memory requested. @return Memory address of allocated pages. **/ UINTN InternalAllocMaxAddressWithGuard ( IN OUT LIST_ENTRY *FreePageList, IN UINTN NumberOfPages, IN UINTN MaxAddress, IN EFI_MEMORY_TYPE MemoryType ) { LIST_ENTRY *Node; FREE_PAGE_LIST *Pages; UINTN PagesToAlloc; UINTN HeadGuard; UINTN TailGuard; UINTN Address; for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) { Pages = BASE_CR (Node, FREE_PAGE_LIST, Link); if (Pages->NumberOfPages >= NumberOfPages && (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) { // // We may need 1 or 2 more pages for Guard. Check it out. // PagesToAlloc = NumberOfPages; TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages); if (!IsGuardPage (TailGuard)) { // // Add one if no Guard at the end of current free memory block. // PagesToAlloc += 1; TailGuard = 0; } HeadGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) - EFI_PAGE_SIZE; if (!IsGuardPage (HeadGuard)) { // // Add one if no Guard at the page before the address to allocate // PagesToAlloc += 1; HeadGuard = 0; } if (Pages->NumberOfPages < PagesToAlloc) { // Not enough space to allocate memory with Guards? Try next block. continue; } Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc, MaxAddress); ConvertSmmMemoryMapEntry(MemoryType, Address, PagesToAlloc, FALSE); CoreFreeMemoryMapStack(); if (HeadGuard == 0) { // Don't pass the Guard page to user. Address += EFI_PAGE_SIZE; } SetGuardForMemory (Address, NumberOfPages); return Address; } } return (UINTN)(-1); }