12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- memory.c
- Abstract:
- This module implements core UEFI memory map services.
- Author:
- Evan Green 27-Feb-2014
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "ueficore.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT EFI_PAGE_SIZE
- #define EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT EFI_PAGE_SIZE
- //
- // Define the maximum number of temporary descriptors that will ever be
- // needed simultaneously.
- //
- #define EFI_DESCRIPTOR_STACK_SIZE 6
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef struct _EFI_MEMORY_TYPE_STATISTICS {
- EFI_PHYSICAL_ADDRESS BaseAddress;
- EFI_PHYSICAL_ADDRESS MaximumAddress;
- UINT64 CurrentPageCount;
- UINT64 PageCount;
- UINTN InformationIndex;
- BOOLEAN Special;
- BOOLEAN Runtime;
- } EFI_MEMORY_TYPE_STATISTICS, *PEFI_MEMORY_TYPE_STATISTICS;
- typedef struct _EFI_MEMORY_TYPE_INFORMATION {
- UINT32 Type;
- UINT32 PageCount;
- } EFI_MEMORY_TYPE_INFORMATION, *PEFI_MEMORY_TYPE_INFORMATION;
- typedef struct _EFI_MEMORY_MAP_ENTRY {
- LIST_ENTRY ListEntry;
- BOOL Temporary;
- EFI_MEMORY_DESCRIPTOR Descriptor;
- } EFI_MEMORY_MAP_ENTRY, *PEFI_MEMORY_MAP_ENTRY;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- EfipCoreAddMemoryDescriptor (
- EFI_MEMORY_TYPE Type,
- EFI_PHYSICAL_ADDRESS Start,
- UINT64 PageCount,
- UINT64 Attribute
- );
- UINT64
- EfipCoreFindFreePages (
- UINT64 MaxAddress,
- UINT64 PageCount,
- EFI_MEMORY_TYPE NewType,
- UINTN Alignment
- );
- UINT64
- EfipCoreFindFreePagesInRange (
- UINT64 MaxAddress,
- UINT64 MinAddress,
- UINT64 PageCount,
- EFI_MEMORY_TYPE NewType,
- UINTN Alignment
- );
- EFI_STATUS
- EfipCoreConvertPages (
- UINT64 Start,
- UINT64 PageCount,
- EFI_MEMORY_TYPE NewType
- );
- VOID
- EfipCoreAddRange (
- EFI_MEMORY_TYPE Type,
- EFI_PHYSICAL_ADDRESS Start,
- EFI_PHYSICAL_ADDRESS End,
- UINT64 Attribute
- );
- EFI_MEMORY_DESCRIPTOR *
- EfipCoreMergeMemoryMapDescriptor (
- EFI_MEMORY_DESCRIPTOR *MemoryMap,
- EFI_MEMORY_DESCRIPTOR *LastDescriptor,
- UINTN DescriptorSize
- );
- VOID
- EfipCoreRemoveMemoryMapEntry (
- PEFI_MEMORY_MAP_ENTRY Entry
- );
- VOID
- EfipCoreFlushMemoryMapStack (
- VOID
- );
- PEFI_MEMORY_MAP_ENTRY
- EfipCoreAllocateMemoryMapEntry (
- VOID
- );
- VOID
- EfipDebugPrintMemoryMap (
- EFI_MEMORY_DESCRIPTOR *Map,
- UINTN MapSize,
- UINTN DescriptorSize
- );
- VOID
- EfipDebugPrintMemoryDescriptor (
- EFI_MEMORY_DESCRIPTOR *Descriptor
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store the memory "lock", which really just helps prevent re-entering
- // functions in a notify ISR.
- //
- EFI_LOCK EfiMemoryLock;
- //
- // Store the memory map itself, which is just a list of EFI_MEMORY_MAP_ENTRY
- // structures.
- //
- LIST_ENTRY EfiMemoryMap;
- //
- // Store the memory map key, essentially a sequence number on the memory map.
- //
- UINTN EfiMemoryMapKey;
- //
- // Store a list of free descriptors to use.
- //
- LIST_ENTRY EfiFreeDescriptorList;
- //
- // Define the default memory range to search.
- //
- EFI_PHYSICAL_ADDRESS EfiDefaultMaximumAddress = MAX_ADDRESS;
- EFI_PHYSICAL_ADDRESS EfiDefaultBaseAddress = MAX_ADDRESS;
- //
- // Define the stack of temporary descriptors used during operations.
- //
- UINTN EfiDescriptorStackSize = 0;
- EFI_MEMORY_MAP_ENTRY EfiDescriptorStack[EFI_DESCRIPTOR_STACK_SIZE];
- BOOLEAN EfiDescriptorStackFreeInProgress = FALSE;
- //
- // Store memory statistics, which help cluster allocations of the same type
- // together.
- //
- BOOLEAN EfiMemoryTypeInformationInitialized = FALSE;
- EFI_MEMORY_TYPE_STATISTICS EfiMemoryStatistics[EfiMaxMemoryType + 1] = {
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE},
- {0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE}
- };
- EFI_MEMORY_TYPE_INFORMATION EfiMemoryTypeInformation[EfiMaxMemoryType + 1] = {
- {EfiReservedMemoryType, 0},
- {EfiLoaderCode, 0},
- {EfiLoaderData, 0},
- {EfiBootServicesCode, 0},
- {EfiBootServicesData, 0},
- {EfiRuntimeServicesCode, 0},
- {EfiRuntimeServicesData, 0},
- {EfiConventionalMemory, 0},
- {EfiUnusableMemory, 0},
- {EfiACPIReclaimMemory, 0},
- {EfiACPIMemoryNVS, 0},
- {EfiMemoryMappedIO, 0},
- {EfiMemoryMappedIOPortSpace, 0},
- {EfiPalCode, 0},
- {EfiMaxMemoryType, 0}
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- EFIAPI
- EFI_STATUS
- EfiCoreAllocatePages (
- EFI_ALLOCATE_TYPE Type,
- EFI_MEMORY_TYPE MemoryType,
- UINTN Pages,
- EFI_PHYSICAL_ADDRESS *Memory
- )
- /*++
- Routine Description:
- This routine allocates memory pages from the system.
- Arguments:
- Type - Supplies the allocation strategy to use.
- MemoryType - Supplies the memory type of the allocation.
- Pages - Supplies the number of contiguous EFI_PAGE_SIZE pages.
- Memory - Supplies a pointer that on input contains a physical address whose
- use depends on the allocation strategy. On output, the physical address
- of the allocation will be returned.
- Return Value:
- EFI_SUCCESS on success.
- EFI_INVALID_PARAMETER if the Type or MemoryType are invalid, or Memory is
- NULL.
- EFI_OUT_OF_RESOURCES if the pages could not be allocated.
- EFI_NOT_FOUND if the requested pages could not be found.
- --*/
- {
- UINTN Alignment;
- UINT64 MaxAddress;
- UINT64 Start;
- EFI_STATUS Status;
- if (Type >= MaxAllocateType) {
- return EFI_INVALID_PARAMETER;
- }
- if ((((UINT32)MemoryType >= EfiMaxMemoryType) &&
- ((UINT32)MemoryType < 0x7FFFFFFF)) ||
- (MemoryType == EfiConventionalMemory)) {
- return EFI_INVALID_PARAMETER;
- }
- if (Memory == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
- if ((MemoryType == EfiACPIReclaimMemory) ||
- (MemoryType == EfiACPIMemoryNVS) ||
- (MemoryType == EfiRuntimeServicesCode) ||
- (MemoryType == EfiRuntimeServicesData)) {
- Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
- }
- if (Type == AllocateAddress) {
- if ((*Memory & (Alignment - 1)) != 0) {
- return EFI_NOT_FOUND;
- }
- }
- Pages += EFI_SIZE_TO_PAGES(Alignment) - 1;
- Pages &= ~(EFI_SIZE_TO_PAGES(Alignment) - 1);
- Start = *Memory;
- MaxAddress = MAX_ADDRESS;
- if (Type == AllocateMaxAddress) {
- MaxAddress = Start;
- }
- EfiCoreAcquireLock(&EfiMemoryLock);
- //
- // If no specific address was requested, then locate some pages.
- //
- if (Type != AllocateAddress) {
- Start = EfipCoreFindFreePages(MaxAddress, Pages, MemoryType, Alignment);
- if (Start == 0) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CoreAllocatePagesEnd;
- }
- }
- //
- // Mark the pages as allocated.
- //
- Status = EfipCoreConvertPages(Start, Pages, MemoryType);
- CoreAllocatePagesEnd:
- EfiCoreReleaseLock(&EfiMemoryLock);
- if (!EFI_ERROR(Status)) {
- *Memory = Start;
- }
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfiCoreFreePages (
- EFI_PHYSICAL_ADDRESS Memory,
- UINTN Pages
- )
- /*++
- Routine Description:
- This routine frees memory pages back to the system.
- Arguments:
- Memory - Supplies the base physical address of the allocation to free.
- Pages - Supplies the number of pages to free.
- Return Value:
- EFI_SUCCESS on success.
- EFI_INVALID_PARAMETER if the memory is not page aligned or is invalid.
- EFI_NOT_FOUND if the requested pages were not allocated.
- --*/
- {
- UINTN Alignment;
- PLIST_ENTRY CurrentEntry;
- PEFI_MEMORY_MAP_ENTRY Entry;
- UINT64 EntryEnd;
- UINT64 EntryStart;
- EFI_STATUS Status;
- EfiCoreAcquireLock(&EfiMemoryLock);
- Entry = NULL;
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry, EFI_MEMORY_MAP_ENTRY, ListEntry);
- EntryStart = Entry->Descriptor.PhysicalStart;
- EntryEnd = EntryStart +
- (Entry->Descriptor.NumberOfPages << EFI_PAGE_SHIFT) - 1;
- if ((EntryStart <= Memory) && (EntryEnd > Memory)) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == &EfiMemoryMap) {
- Status = EFI_NOT_FOUND;
- goto CoreFreePagesEnd;
- }
- Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
- ASSERT(Entry != NULL);
- if ((Entry->Descriptor.Type == EfiACPIReclaimMemory) ||
- (Entry->Descriptor.Type == EfiACPIMemoryNVS) ||
- (Entry->Descriptor.Type == EfiRuntimeServicesCode) ||
- (Entry->Descriptor.Type == EfiRuntimeServicesData)) {
- Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
- }
- if ((Memory & (Alignment - 1)) != 0) {
- Status = EFI_INVALID_PARAMETER;
- goto CoreFreePagesEnd;
- }
- Pages += EFI_SIZE_TO_PAGES(Alignment) - 1;
- Pages &= ~(EFI_SIZE_TO_PAGES(Alignment) - 1);
- Status = EfipCoreConvertPages(Memory, Pages, EfiConventionalMemory);
- if (EFI_ERROR(Status)) {
- goto CoreFreePagesEnd;
- }
- CoreFreePagesEnd:
- EfiCoreReleaseLock(&EfiMemoryLock);
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfiCoreGetMemoryMap (
- UINTN *MemoryMapSize,
- EFI_MEMORY_DESCRIPTOR *MemoryMap,
- UINTN *MapKey,
- UINTN *DescriptorSize,
- UINT32 *DescriptorVersion
- )
- /*++
- Routine Description:
- This routine returns the current memory map.
- Arguments:
- MemoryMapSize - Supplies a pointer to the size, in bytes, of the memory
- map buffer. On input, this is the size of the buffer allocated by the
- caller. On output, this is the size of the buffer returned by the
- firmware if the buffer was large enough, or the size of the buffer
- needed if the buffer was too small.
- MemoryMap - Supplies a pointer to a caller-allocated buffer where the
- memory map will be written on success.
- MapKey - Supplies a pointer where the firmware returns the map key.
- DescriptorSize - Supplies a pointer where the firmware returns the size of
- the EFI_MEMORY_DESCRIPTOR structure.
- DescriptorVersion - Supplies a pointer where the firmware returns the
- version number associated with the EFI_MEMORY_DESCRIPTOR structure.
- Return Value:
- EFI_SUCCESS on success.
- EFI_BUFFER_TOO_SMALL if the supplied buffer was too small. The size needed
- is returned in the size parameter.
- EFI_INVALID_PARAMETER if the supplied size or memory map pointers are NULL.
- --*/
- {
- UINTN BufferSize;
- PLIST_ENTRY CurrentEntry;
- PEFI_MEMORY_MAP_ENTRY Entry;
- UINT64 EntryEnd;
- UINT64 EntryStart;
- EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
- UINTN Size;
- EFI_STATUS Status;
- EFI_MEMORY_TYPE Type;
- if (MemoryMapSize == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- Size = sizeof(EFI_MEMORY_DESCRIPTOR);
- //
- // Artificially change the reported size to foil folks using pointer
- // arithmetic. This forces them to use the returned descriptor size.
- //
- Size += sizeof(UINT64) - (Size % sizeof(UINT64));
- if (DescriptorSize != NULL) {
- *DescriptorSize = Size;
- }
- if (DescriptorVersion != NULL) {
- *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
- }
- EfiCoreAcquireLock(&EfiMemoryLock);
- //
- // Compute the size required to contain the entire map.
- //
- BufferSize = 0;
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry, EFI_MEMORY_MAP_ENTRY, ListEntry);
- BufferSize += Size;
- CurrentEntry = CurrentEntry->Next;
- }
- if (*MemoryMapSize < BufferSize) {
- Status = EFI_BUFFER_TOO_SMALL;
- goto CoreGetMemoryMapEnd;
- }
- if (MemoryMap == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto CoreGetMemoryMapEnd;
- }
- //
- // Build the memory map.
- //
- EfiCoreSetMemory(MemoryMap, BufferSize, 0);
- MemoryMapStart = MemoryMap;
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry, EFI_MEMORY_MAP_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- ASSERT(Entry->Descriptor.VirtualStart == 0);
- EfiCoreCopyMemory(MemoryMap,
- &(Entry->Descriptor),
- sizeof(EFI_MEMORY_DESCRIPTOR));
- //
- // If the memory type is free memory, then determine if the range is
- // part of a memory type bin and needs to be converted to the same
- // memory type as the rest of the memory type bin in order to minimize
- // EFI memory map changes across reboots. This improves the chances for
- // a successful S4 resume in the presence of minor page allocation
- // differences across reboots.
- //
- if (MemoryMap->Type == EfiConventionalMemory) {
- EntryStart = Entry->Descriptor.PhysicalStart;
- EntryEnd = EntryStart +
- (Entry->Descriptor.NumberOfPages << EFI_PAGE_SHIFT) - 1;
- for (Type = 0; Type < EfiMaxMemoryType; Type += 1) {
- if ((EfiMemoryStatistics[Type].Special != FALSE) &&
- (EfiMemoryStatistics[Type].PageCount > 0) &&
- (EntryStart >= EfiMemoryStatistics[Type].BaseAddress) &&
- (EntryEnd <= EfiMemoryStatistics[Type].MaximumAddress)) {
- MemoryMap->Type = Type;
- }
- }
- }
- if ((MemoryMap->Type < EfiMaxMemoryType) &&
- (EfiMemoryStatistics[MemoryMap->Type].Runtime != FALSE)) {
- MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
- }
- //
- // Check to see if the new memory map descriptor can be merged with an
- // existing descriptor.
- //
- MemoryMap = EfipCoreMergeMemoryMapDescriptor(MemoryMapStart,
- MemoryMap,
- Size);
- }
- //
- // Compute the buffer size actually used after all the merge operations.
- //
- BufferSize = (UINTN)MemoryMap - (UINTN)MemoryMapStart;
- Status = EFI_SUCCESS;
- CoreGetMemoryMapEnd:
- if (MapKey != NULL) {
- *MapKey = EfiMemoryMapKey;
- }
- EfiCoreReleaseLock(&EfiMemoryLock);
- *MemoryMapSize = BufferSize;
- return Status;
- }
- VOID *
- EfiCoreAllocatePoolPages (
- EFI_MEMORY_TYPE PoolType,
- UINTN PageCount,
- UINTN Alignment
- )
- /*++
- Routine Description:
- This routine allocates pages to back pool allocations and memory map
- descriptors.
- Arguments:
- PoolType - Supplies the memory type of the allocation.
- PageCount - Supplies the number of pages to allocate.
- Alignment - Supplies the required alignment.
- Return Value:
- Returns a pointer to the allocated memory on success.
- NULL on allocation failure.
- --*/
- {
- UINT64 Start;
- Start = EfipCoreFindFreePages(MAX_ADDRESS, PageCount, PoolType, Alignment);
- ASSERT(Start != 0);
- if (Start != 0) {
- EfipCoreConvertPages(Start, PageCount, PoolType);
- }
- return (VOID *)(UINTN)Start;
- }
- VOID
- EfiCoreFreePoolPages (
- EFI_PHYSICAL_ADDRESS Memory,
- UINTN PageCount
- )
- /*++
- Routine Description:
- This routine frees pages allocated for pool or descriptor.
- Arguments:
- Memory - Supplies the address of the allocation.
- PageCount - Supplies the number of pages to free.
- Return Value:
- None.
- --*/
- {
- EfipCoreConvertPages(Memory, PageCount, EfiConventionalMemory);
- return;
- }
- EFI_STATUS
- EfiCoreInitializeMemoryServices (
- VOID *FirmwareLowestAddress,
- UINTN FirmwareSize,
- VOID *StackBase,
- UINTN StackSize
- )
- /*++
- Routine Description:
- This routine initializes core UEFI memory services.
- Arguments:
- FirmwareLowestAddress - Supplies the lowest address where the firmware was
- loaded into memory.
- FirmwareSize - Supplies the size of the firmware image in memory, in bytes.
- StackBase - Supplies the base (lowest) address of the stack.
- StackSize - Supplies the size in bytes of the stack. This should be at
- least 0x4000 bytes (16kB).
- Return Value:
- EFI status code.
- --*/
- {
- EFI_MEMORY_DESCRIPTOR *Entry;
- EFI_PHYSICAL_ADDRESS EntryAddress;
- EFI_MEMORY_DESCRIPTOR *FreeEntry;
- UINTN Index;
- EFI_MEMORY_DESCRIPTOR *PlatformMap;
- UINTN PlatformMapSize;
- EFI_STATUS Status;
- EfiCoreInitializeLock(&EfiMemoryLock, TPL_NOTIFY);
- INITIALIZE_LIST_HEAD(&EfiMemoryMap);
- INITIALIZE_LIST_HEAD(&EfiFreeDescriptorList);
- //
- // Get the blank platform memory map.
- //
- Status = EfiPlatformGetInitialMemoryMap(&PlatformMap, &PlatformMapSize);
- if (EFI_ERROR(Status)) {
- goto CoreInitializeMemoryServicesEnd;
- }
- //
- // Find the biggest free descriptor and add that one first.
- //
- FreeEntry = NULL;
- for (Index = 0; Index < PlatformMapSize; Index += 1) {
- Entry = &(PlatformMap[Index]);
- if ((Entry->Type == EfiConventionalMemory) &&
- (Entry->PhysicalStart < MAX_ADDRESS) &&
- ((FreeEntry == NULL) ||
- (Entry->NumberOfPages > FreeEntry->NumberOfPages))) {
- FreeEntry = Entry;
- }
- }
- if (FreeEntry == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CoreInitializeMemoryServicesEnd;
- }
- EfipCoreAddMemoryDescriptor(FreeEntry->Type,
- FreeEntry->PhysicalStart,
- FreeEntry->NumberOfPages,
- FreeEntry->Attribute);
- //
- // Now add all the other entries.
- //
- for (Index = 0; Index < PlatformMapSize; Index += 1) {
- Entry = &(PlatformMap[Index]);
- if (Entry == FreeEntry) {
- continue;
- }
- EfipCoreAddMemoryDescriptor(Entry->Type,
- Entry->PhysicalStart,
- Entry->NumberOfPages,
- Entry->Attribute);
- }
- Status = EfiCoreInitializePool();
- if (EFI_ERROR(Status)) {
- goto CoreInitializeMemoryServicesEnd;
- }
- //
- // Add the firmware image and stack as boot services code and data.
- //
- EntryAddress = (UINTN)FirmwareLowestAddress & ~EFI_PAGE_MASK;
- FirmwareSize += (UINTN)FirmwareLowestAddress & EFI_PAGE_MASK;
- Status = EfiCoreAllocatePages(AllocateAddress,
- EfiBootServicesCode,
- EFI_SIZE_TO_PAGES(FirmwareSize),
- &EntryAddress);
- if (EFI_ERROR(Status)) {
- RtlDebugPrint("Failed to add firmware image to memory map.\n");
- goto CoreInitializeMemoryServicesEnd;
- }
- EntryAddress = (UINTN)StackBase;
- ASSERT((EntryAddress & EFI_PAGE_MASK) == 0);
- ASSERT((StackSize & EFI_PAGE_MASK) == 0);
- Status = EfiCoreAllocatePages(AllocateAddress,
- EfiBootServicesData,
- EFI_SIZE_TO_PAGES(StackSize),
- &EntryAddress);
- if (EFI_ERROR(Status)) {
- RtlDebugPrint("Failed to add firmware stack to memory map.\n");
- goto CoreInitializeMemoryServicesEnd;
- }
- CoreInitializeMemoryServicesEnd:
- return Status;
- }
- EFI_STATUS
- EfiCoreTerminateMemoryServices (
- UINTN MapKey
- )
- /*++
- Routine Description:
- This routine terminates memory services.
- Arguments:
- MapKey - Supplies the map key reported by the boot application. This is
- checked against the current map key to ensure the boot application has
- an up to date view of the world.
- Return Value:
- EFI_SUCCESS on success.
- EFI_INVALID_PARAMETER if the map key is not valid or the memory map is
- not consistent.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PEFI_MEMORY_MAP_ENTRY Entry;
- EFI_STATUS Status;
- Status = EFI_SUCCESS;
- EfiCoreAcquireLock(&EfiMemoryLock);
- if (MapKey == EfiMemoryMapKey) {
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry, EFI_MEMORY_MAP_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if ((Entry->Descriptor.Attribute & EFI_MEMORY_RUNTIME) != 0) {
- if ((Entry->Descriptor.Type == EfiACPIReclaimMemory) ||
- (Entry->Descriptor.Type == EfiACPIMemoryNVS)) {
- RtlDebugPrint("ExitBootServices: ACPI memory entry has "
- "Runtime attribute set!\n");
- Status = EFI_INVALID_PARAMETER;
- goto CoreTerminateMemoryServicesEnd;
- }
- if ((Entry->Descriptor.PhysicalStart &
- (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
- RtlDebugPrint("ExitBootServices: Runtime entry is not "
- "aligned.\n");
- Status = EFI_INVALID_PARAMETER;
- goto CoreTerminateMemoryServicesEnd;
- }
- }
- }
- //
- // The boot application has a stale copy of the memory map. Fail.
- //
- } else {
- Status = EFI_INVALID_PARAMETER;
- }
- CoreTerminateMemoryServicesEnd:
- EfiCoreReleaseLock(&EfiMemoryLock);
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- EfipCoreAddMemoryDescriptor (
- EFI_MEMORY_TYPE Type,
- EFI_PHYSICAL_ADDRESS Start,
- UINT64 PageCount,
- UINT64 Attribute
- )
- /*++
- Routine Description:
- This routine is called to initialize the memory map and add descriptors.
- The first descriptor added must be general usable memory.
- Arguments:
- Type - Supplies the type of memory to add.
- Start - Supplies the starting physical address. This must be page aligned.
- PageCount - Supplies the number of pages being described.
- Attribute - Supplies the memory attributes of the region.
- Return Value:
- None.
- --*/
- {
- EFI_PHYSICAL_ADDRESS End;
- UINTN FreeIndex;
- UINTN Index;
- EFI_STATUS Status;
- if ((Start & EFI_PAGE_MASK) != 0) {
- return;
- }
- if ((Type >= EfiMaxMemoryType) && (Type < 0x7FFFFFFF)) {
- return;
- }
- EfiCoreAcquireLock(&EfiMemoryLock);
- End = Start + EFI_PAGES_TO_SIZE(PageCount) - 1;
- EfipCoreAddRange(Type, Start, End, Attribute);
- EfipCoreFlushMemoryMapStack();
- EfiCoreReleaseLock(&EfiMemoryLock);
- //
- // The rest of this function initializes the memory statistics.
- //
- if (EfiMemoryTypeInformationInitialized != FALSE) {
- return;
- }
- //
- // Loop through each memory type in the order specified by the type
- // information array.
- //
- for (Index = 0;
- EfiMemoryTypeInformation[Index].Type != EfiMaxMemoryType;
- Index += 1) {
- Type = (EFI_MEMORY_TYPE)(EfiMemoryTypeInformation[Index].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
- if (EfiMemoryTypeInformation[Index].PageCount == 0) {
- continue;
- }
- //
- // Allocate pages for the memory type from the top of available memory.
- //
- Status = EfiCoreAllocatePages(AllocateAnyPages,
- Type,
- EfiMemoryTypeInformation[Index].PageCount,
- &(EfiMemoryStatistics[Type].BaseAddress));
- if (EFI_ERROR(Status)) {
- //
- // If an error occurred, free all pages allocated for the previous
- // memory types.
- //
- for (FreeIndex = 0; FreeIndex < Index; FreeIndex += 1) {
- Type =
- (EFI_MEMORY_TYPE)(EfiMemoryTypeInformation[FreeIndex].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
- if (EfiMemoryTypeInformation[FreeIndex].PageCount != 0) {
- EfiCoreFreePages(
- EfiMemoryStatistics[Type].BaseAddress,
- EfiMemoryTypeInformation[FreeIndex].PageCount);
- EfiMemoryStatistics[Type].BaseAddress = 0;
- EfiMemoryStatistics[Type].MaximumAddress = MAX_ADDRESS;
- }
- }
- return;
- }
- //
- // Compute the address at the top of the current statistics.
- //
- EfiMemoryStatistics[Type].MaximumAddress =
- EfiMemoryStatistics[Type].BaseAddress +
- EFI_PAGES_TO_SIZE(EfiMemoryTypeInformation[Index].PageCount) - 1;
- //
- // If the current base address is the lowest so far, update the default
- // max address.
- //
- if (EfiMemoryStatistics[Type].BaseAddress < EfiDefaultMaximumAddress) {
- EfiDefaultMaximumAddress =
- EfiMemoryStatistics[Type].BaseAddress - 1;
- }
- }
- //
- // There was enough system memory for all the memory types. Free those
- // allocated pages now, and now future allocations of that type will fit
- // into those slots. This avoids fragmentation.
- //
- for (Index = 0;
- EfiMemoryTypeInformation[Index].Type != EfiMaxMemoryType;
- Index += 1) {
- Type = (EFI_MEMORY_TYPE)(EfiMemoryTypeInformation[Index].Type);
- if ((UINT32)Type > EfiMaxMemoryType) {
- continue;
- }
- if (EfiMemoryTypeInformation[Index].PageCount == 0) {
- continue;
- }
- EfiCoreFreePages(EfiMemoryStatistics[Type].BaseAddress,
- EfiMemoryTypeInformation[Index].PageCount);
- EfiMemoryStatistics[Type].PageCount =
- EfiMemoryTypeInformation[Index].PageCount;
- EfiMemoryTypeInformation[Index].PageCount = 0;
- }
- //
- // If the number of pages reserved for a memory type is zero, then all
- // allocations for that type should be in the default range.
- //
- for (Type = (EFI_MEMORY_TYPE)0;
- Type < EfiMaxMemoryType;
- Type += 1) {
- for (Index = 0;
- EfiMemoryTypeInformation[Index].Type != EfiMaxMemoryType;
- Index += 1) {
- if (Type == (EFI_MEMORY_TYPE)EfiMemoryTypeInformation[Index].Type) {
- EfiMemoryStatistics[Type].InformationIndex = Index;
- }
- }
- EfiMemoryStatistics[Type].CurrentPageCount = 0;
- if (EfiMemoryStatistics[Type].MaximumAddress == MAX_ADDRESS) {
- EfiMemoryStatistics[Type].MaximumAddress = EfiDefaultMaximumAddress;
- }
- }
- EfiMemoryTypeInformationInitialized = TRUE;
- return;
- }
- UINT64
- EfipCoreFindFreePages (
- UINT64 MaxAddress,
- UINT64 PageCount,
- EFI_MEMORY_TYPE NewType,
- UINTN Alignment
- )
- /*++
- Routine Description:
- This routine attempts to find a consecutive range of free pages below the
- given maximum address.
- Arguments:
- MaxAddress - Supplies the maximum address that the allocation must stay
- below.
- PageCount - Supplies the number of pages to allocate.
- NewType - Supplies the type of memory this range is going to be turned into.
- Alignment - Supplies the required alignment of the allocation.
- Return Value:
- Returns the physical address of the base of the allocation on success.
- 0 if the range was not found.
- --*/
- {
- UINT64 Start;
- //
- // First try to find free pages in the range where there are already
- // descriptors of this type hanging around.
- //
- if (((UINT32)NewType < EfiMaxMemoryType) &&
- (MaxAddress >= EfiMemoryStatistics[NewType].MaximumAddress)) {
- Start = EfipCoreFindFreePagesInRange(
- EfiMemoryStatistics[NewType].MaximumAddress,
- EfiMemoryStatistics[NewType].BaseAddress,
- PageCount,
- NewType,
- Alignment);
- if (Start != 0) {
- return Start;
- }
- }
- //
- // Attempt to find free pages in the default area.
- //
- if (MaxAddress >= EfiDefaultMaximumAddress) {
- Start = EfipCoreFindFreePagesInRange(EfiDefaultMaximumAddress,
- 0,
- PageCount,
- NewType,
- Alignment);
- if (Start != 0) {
- if (Start < EfiDefaultBaseAddress) {
- EfiDefaultBaseAddress = Start;
- }
- return Start;
- }
- }
- //
- // Find free pages anywhere in the specified range. This is the most
- // permissive search. If this doesn't work, it's not happening.
- //
- Start = EfipCoreFindFreePagesInRange(MaxAddress,
- 0,
- PageCount,
- NewType,
- Alignment);
- return Start;
- }
- UINT64
- EfipCoreFindFreePagesInRange (
- UINT64 MaxAddress,
- UINT64 MinAddress,
- UINT64 PageCount,
- EFI_MEMORY_TYPE NewType,
- UINTN Alignment
- )
- /*++
- Routine Description:
- This routine attempts to find a consecutive range of free pages within the
- specified range.
- Arguments:
- MaxAddress - Supplies the maximum address that the allocation must stay
- below.
- MinAddress - Supplies the minimum address that the allocation must stay
- at or above.
- PageCount - Supplies the number of pages to allocate.
- NewType - Supplies the type of memory this range is going to be turned into.
- Alignment - Supplies the required alignment of the allocation.
- Return Value:
- Returns the physical address of the base of the allocation on success.
- 0 if the range was not found.
- --*/
- {
- UINT64 ByteCount;
- PLIST_ENTRY CurrentEntry;
- PEFI_MEMORY_MAP_ENTRY Entry;
- UINT64 EntryEnd;
- UINT64 EntrySize;
- UINT64 EntryStart;
- UINT64 Target;
- if ((MaxAddress < EFI_PAGE_MASK) || (PageCount == 0)) {
- return 0;
- }
- //
- // Chop the max address down if it's not one below a page boundary.
- //
- if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
- MaxAddress -= EFI_PAGE_MASK + 1;
- MaxAddress &= ~EFI_PAGE_MASK;
- MaxAddress |= EFI_PAGE_MASK;
- }
- ByteCount = PageCount << EFI_PAGE_SHIFT;
- Target = 0;
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry, EFI_MEMORY_MAP_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Entry->Descriptor.Type != EfiConventionalMemory) {
- continue;
- }
- EntryStart = Entry->Descriptor.PhysicalStart;
- EntryEnd = EntryStart +
- (Entry->Descriptor.NumberOfPages << EFI_PAGE_SHIFT);
- //
- // Skip descriptors that are outside of the requested range.
- //
- if ((EntryStart >= MaxAddress) || (EntryEnd < MinAddress)) {
- continue;
- }
- //
- // If the descriptor ends past the maximum allowed address, clip it.
- //
- if (EntryEnd > MaxAddress) {
- EntryEnd = MaxAddress;
- }
- EntryEnd = ((EntryEnd + 1) & (~(Alignment - 1))) - 1;
- //
- // If the entry is big enough, and does not dip below the minimum
- // address, then it works.
- //
- EntrySize = EntryEnd - EntryStart + 1;
- if (EntrySize >= ByteCount) {
- if ((EntryEnd - ByteCount + 1) < MinAddress) {
- continue;
- }
- //
- // If this is the highest match, save it.
- //
- if (EntryEnd > Target) {
- Target = EntryEnd;
- }
- }
- }
- if (Target == 0) {
- return 0;
- }
- ASSERT(Target > ByteCount);
- Target -= ByteCount - 1;
- if ((Target & EFI_PAGE_MASK) != 0) {
- return 0;
- }
- return Target;
- }
- EFI_STATUS
- EfipCoreConvertPages (
- UINT64 Start,
- UINT64 PageCount,
- EFI_MEMORY_TYPE NewType
- )
- /*++
- Routine Description:
- This routine converts a given range to the specified type. The range must
- already exist in the memory map.
- Arguments:
- Start - Supplies the first address in the range. This must be page aligned.
- PageCount - Supplies the number of pages in the range.
- NewType - Supplies the type to convert the pages to.
- Return Value:
- EFI_SUCCESS on success.
- EFI_INVALID_PARAMETER if the page count is zero, the address is not
- aligned, or the type is invalid.
- EFI_NOT_FOUND if no existing descriptor covers the given region.
- --*/
- {
- UINT64 Attribute;
- UINT64 ByteCount;
- PLIST_ENTRY CurrentEntry;
- UINT64 End;
- PEFI_MEMORY_MAP_ENTRY Entry;
- UINT64 EntryEnd;
- UINT64 EntryStart;
- EFI_MEMORY_TYPE EntryType;
- UINTN InformationIndex;
- PEFI_MEMORY_MAP_ENTRY NewEntry;
- UINT64 RangeEnd;
- ByteCount = PageCount << EFI_PAGE_SHIFT;
- Entry = NULL;
- End = Start + ByteCount - 1;
- ASSERT((PageCount != 0) && ((Start & EFI_PAGE_MASK) == 0) &&
- (End > Start) && (EfiCoreIsLockHeld(&EfiMemoryLock) != FALSE));
- if ((PageCount == 0) || ((Start & EFI_PAGE_MASK) != 0) ||
- (Start > Start + ByteCount)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Loop until the entire range is converted.
- //
- while (Start < End) {
- //
- // Loop through looking for the descriptor that contains this range.
- //
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry, EFI_MEMORY_MAP_ENTRY, ListEntry);
- EntryStart = Entry->Descriptor.PhysicalStart;
- EntryEnd = EntryStart +
- (Entry->Descriptor.NumberOfPages << EFI_PAGE_SHIFT) - 1;
- if ((EntryStart <= Start) && (EntryEnd > Start)) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == &EfiMemoryMap) {
- return EFI_NOT_FOUND;
- }
- //
- // Convert the range to the end, or to the end of the descriptor if the
- // range covers more than the descriptor.
- //
- RangeEnd = End;
- if (EntryEnd < End) {
- RangeEnd = EntryEnd;
- }
- //
- // Verify the conversion is allowed.
- //
- EntryType = Entry->Descriptor.Type;
- if (NewType == EfiConventionalMemory) {
- if (EntryType == EfiConventionalMemory) {
- return EFI_NOT_FOUND;
- }
- } else {
- if (EntryType != EfiConventionalMemory) {
- return EFI_NOT_FOUND;
- }
- }
- //
- // Update the counters for the number of pages allocated to each
- // memory type.
- //
- if ((UINT32)EntryType < EfiMaxMemoryType) {
- if (((Start >= EfiMemoryStatistics[EntryType].BaseAddress) &&
- (Start <= EfiMemoryStatistics[EntryType].MaximumAddress)) ||
- ((Start >= EfiDefaultBaseAddress) &&
- (Start <= EfiDefaultMaximumAddress))) {
- if (PageCount >=
- EfiMemoryStatistics[EntryType].CurrentPageCount) {
- EfiMemoryStatistics[EntryType].CurrentPageCount = 0;
- } else {
- EfiMemoryStatistics[EntryType].CurrentPageCount -=
- PageCount;
- }
- }
- }
- if ((UINT32)NewType < EfiMaxMemoryType) {
- if (((Start > EfiMemoryStatistics[NewType].BaseAddress) &&
- (Start <= EfiMemoryStatistics[NewType].MaximumAddress)) ||
- ((Start >= EfiDefaultBaseAddress) &&
- (Start <= EfiDefaultMaximumAddress))) {
- EfiMemoryStatistics[NewType].CurrentPageCount += PageCount;
- InformationIndex =
- EfiMemoryStatistics[NewType].InformationIndex;
- if (EfiMemoryStatistics[NewType].CurrentPageCount >
- EfiMemoryTypeInformation[InformationIndex].PageCount) {
- EfiMemoryTypeInformation[InformationIndex].PageCount =
- (UINT32)EfiMemoryStatistics[NewType].CurrentPageCount;
- }
- }
- }
- //
- // Pull the requested range out of the descriptor.
- //
- if (EntryStart == Start) {
- EntryStart = RangeEnd + 1;
- } else if (EntryEnd == RangeEnd) {
- EntryEnd = Start - 1;
- //
- // The descriptor is being split in two. Clip the end of current one
- // and add a new one for the remainder.
- //
- } else {
- ASSERT(EfiDescriptorStackSize < EFI_DESCRIPTOR_STACK_SIZE);
- NewEntry = &(EfiDescriptorStack[EfiDescriptorStackSize]);
- EfiDescriptorStackSize += 1;
- NewEntry->Temporary = TRUE;
- NewEntry->Descriptor.Type = EntryType;
- NewEntry->Descriptor.PhysicalStart = RangeEnd + 1;
- NewEntry->Descriptor.VirtualStart = 0;
- NewEntry->Descriptor.NumberOfPages =
- (EntryEnd + 1 - RangeEnd) >> EFI_PAGE_SHIFT;
- NewEntry->Descriptor.Attribute = Entry->Descriptor.Attribute;
- EntryEnd = Start - 1;
- ASSERT(EntryStart < EntryEnd);
- INSERT_BEFORE(&(NewEntry->ListEntry), &EfiMemoryMap);
- }
- Attribute = Entry->Descriptor.Attribute;
- if (EntryStart == EntryEnd + 1) {
- EfipCoreRemoveMemoryMapEntry(Entry);
- Entry = NULL;
- } else {
- Entry->Descriptor.PhysicalStart = EntryStart;
- Entry->Descriptor.NumberOfPages =
- (EntryEnd + 1 - EntryStart) >> EFI_PAGE_SHIFT;
- }
- //
- // Add the new range in.
- //
- EfipCoreAddRange(NewType, Start, RangeEnd, Attribute);
- //
- // Flush the temporary descriptors out to real descriptors.
- //
- EfipCoreFlushMemoryMapStack();
- //
- // Move on to the next range.
- //
- Start = RangeEnd + 1;
- }
- return EFI_SUCCESS;
- }
- VOID
- EfipCoreAddRange (
- EFI_MEMORY_TYPE Type,
- EFI_PHYSICAL_ADDRESS Start,
- EFI_PHYSICAL_ADDRESS End,
- UINT64 Attribute
- )
- /*++
- Routine Description:
- This routine adds a range to the memory map. The range must not already
- exist in the memory map.
- Arguments:
- Type - Supplies the memory type of the range.
- Start - Supplies the starting address of the range. This must be page
- aligned.
- End - Supplies the ending address of the range, inclusive. This must be the
- last byte of a page.
- Attribute - Supplies the attributes of the range to add.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PEFI_MEMORY_MAP_ENTRY Entry;
- UINT64 EntryEnd;
- UINT64 EntryStart;
- PEFI_MEMORY_MAP_ENTRY NewEntry;
- ASSERT((Start & EFI_PAGE_MASK) == 0);
- ASSERT(End > Start);
- ASSERT(EfiCoreIsLockHeld(&EfiMemoryLock) != FALSE);
- //
- // If free memory is being added that includes page zero, zero out that
- // page.
- //
- if ((Type == EfiConventionalMemory) &&
- (Start == 0) &&
- (End >= EFI_PAGE_SIZE - 1)) {
- EfiCoreSetMemory((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
- }
- //
- // The memory map is being altered, so update the map key.
- //
- EfiMemoryMapKey += 1;
- //
- // Notify the event group wired to listen for memory map changes.
- // Since the TPL is raised the notification functions will only be called
- // after the lock is released.
- //
- EfipCoreNotifySignalList(&EfiEventMemoryMapChangeGuid);
- //
- // Look for descriptors to coalesce with.
- //
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry, EFI_MEMORY_MAP_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Entry->Descriptor.Type != Type) {
- continue;
- }
- if (Entry->Descriptor.Attribute != Attribute) {
- continue;
- }
- EntryStart = Entry->Descriptor.PhysicalStart;
- EntryEnd = EntryStart +
- (Entry->Descriptor.NumberOfPages << EFI_PAGE_SHIFT) - 1;
- if (EntryEnd + 1 == EntryStart) {
- Start = EntryStart;
- EfipCoreRemoveMemoryMapEntry(Entry);
- } else if (EntryStart == End + 1) {
- End = EntryEnd;
- EfipCoreRemoveMemoryMapEntry(Entry);
- }
- }
- //
- // Add the new descriptor.
- //
- ASSERT(EfiDescriptorStackSize < EFI_DESCRIPTOR_STACK_SIZE);
- NewEntry = &(EfiDescriptorStack[EfiDescriptorStackSize]);
- EfiDescriptorStackSize += 1;
- NewEntry->Temporary = TRUE;
- NewEntry->Descriptor.Type = Type;
- NewEntry->Descriptor.PhysicalStart = Start;
- NewEntry->Descriptor.VirtualStart = 0;
- NewEntry->Descriptor.NumberOfPages = (End + 1 - Start) >> EFI_PAGE_SHIFT;
- NewEntry->Descriptor.Attribute = Attribute;
- INSERT_BEFORE(&(NewEntry->ListEntry), &EfiMemoryMap);
- return;
- }
- EFI_MEMORY_DESCRIPTOR *
- EfipCoreMergeMemoryMapDescriptor (
- EFI_MEMORY_DESCRIPTOR *MemoryMap,
- EFI_MEMORY_DESCRIPTOR *LastDescriptor,
- UINTN DescriptorSize
- )
- /*++
- Routine Description:
- This routine checks to see if memory descriptros can be merged together.
- Descriptors qualify for merging if they are adjacent and have the same
- attributes.
- Arguments:
- MemoryMap - Supplies a pointer to the start of the memory map.
- LastDescriptor - Supplies a pointer to the last descriptor in the map.
- DescriptorSize - Supplies the size of an individual EFI memory descriptor.
- Return Value:
- Returns a pointer to the next available descriptor in the memory map.
- --*/
- {
- //
- // Loop over each entry in the map.
- //
- while (MemoryMap != LastDescriptor) {
- if ((MemoryMap->Type != LastDescriptor->Type) ||
- (MemoryMap->Attribute != LastDescriptor->Attribute)) {
- MemoryMap =
- (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + DescriptorSize);
- continue;
- }
- //
- // Check to see if the given descriptor is immediately above this
- // descriptor.
- //
- if (MemoryMap->PhysicalStart +
- EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages) ==
- LastDescriptor->PhysicalStart) {
- MemoryMap->NumberOfPages += LastDescriptor->NumberOfPages;
- return LastDescriptor;
- }
- //
- // Check to see if the last descriptor is immediately below this one.
- //
- if (MemoryMap->PhysicalStart -
- EFI_PAGES_TO_SIZE((UINTN)LastDescriptor->NumberOfPages) ==
- LastDescriptor->PhysicalStart) {
- MemoryMap->PhysicalStart = LastDescriptor->PhysicalStart;
- MemoryMap->VirtualStart = LastDescriptor->VirtualStart;
- MemoryMap->NumberOfPages += LastDescriptor->NumberOfPages;
- return LastDescriptor;
- }
- //
- // Move on to the next descriptor.
- //
- MemoryMap =
- (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + DescriptorSize);
- }
- //
- // Nothing coalesces, the next descriptor is the one after the last one.
- //
- LastDescriptor = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)LastDescriptor +
- DescriptorSize);
- return LastDescriptor;
- }
- VOID
- EfipCoreRemoveMemoryMapEntry (
- PEFI_MEMORY_MAP_ENTRY Entry
- )
- /*++
- Routine Description:
- This routine removes a descriptor entry and places it on a free list for
- later use.
- Arguments:
- Entry - Supplies a pointer to the entry to remove.
- Return Value:
- None.
- --*/
- {
- LIST_REMOVE(&(Entry->ListEntry));
- Entry->ListEntry.Next = NULL;
- if (Entry->Temporary == FALSE) {
- INSERT_BEFORE(&(Entry->ListEntry), &EfiFreeDescriptorList);
- }
- return;
- }
- VOID
- EfipCoreFlushMemoryMapStack (
- VOID
- )
- /*++
- Routine Description:
- This routine replaces all temporary memory map entries with real allocated
- memory map entries.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PEFI_MEMORY_MAP_ENTRY Entry;
- PEFI_MEMORY_MAP_ENTRY NewEntry;
- PEFI_MEMORY_MAP_ENTRY StackEntry;
- //
- // Avoid re-entering this function.
- //
- if (EfiDescriptorStackFreeInProgress != FALSE) {
- return;
- }
- EfiDescriptorStackFreeInProgress = TRUE;
- while (EfiDescriptorStackSize != 0) {
- NewEntry = EfipCoreAllocateMemoryMapEntry();
- ASSERT(NewEntry != NULL);
- EfiDescriptorStackSize -= 1;
- StackEntry = &(EfiDescriptorStack[EfiDescriptorStackSize]);
- //
- // If it's in the memory map, then create a replacement copy.
- //
- if (StackEntry->ListEntry.Next != NULL) {
- LIST_REMOVE(&(StackEntry->ListEntry));
- StackEntry->ListEntry.Next = NULL;
- EfiCoreCopyMemory(NewEntry,
- StackEntry,
- sizeof(EFI_MEMORY_MAP_ENTRY));
- NewEntry->Temporary = FALSE;
- //
- // Find the proper insertion location.
- //
- CurrentEntry = EfiMemoryMap.Next;
- while (CurrentEntry != &EfiMemoryMap) {
- Entry = LIST_VALUE(CurrentEntry,
- EFI_MEMORY_MAP_ENTRY,
- ListEntry);
- if ((Entry->Temporary == FALSE) &&
- (Entry->Descriptor.PhysicalStart >
- NewEntry->Descriptor.PhysicalStart)) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- INSERT_BEFORE(&(NewEntry->ListEntry), CurrentEntry);
- //
- // This descriptor was already removed, so the descriptor just
- // allocated isn't needed.
- //
- } else {
- INSERT_AFTER(&(NewEntry->ListEntry), &EfiFreeDescriptorList);
- }
- }
- EfiDescriptorStackFreeInProgress = FALSE;
- return;
- }
- PEFI_MEMORY_MAP_ENTRY
- EfipCoreAllocateMemoryMapEntry (
- VOID
- )
- /*++
- Routine Description:
- This routine allocates a new memory map entry. It uses the free list to
- reuse previous descriptors. If that's empty, it allocates a page from the
- memory map and uses that to create more descriptors.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PEFI_MEMORY_MAP_ENTRY Entries;
- PEFI_MEMORY_MAP_ENTRY Entry;
- UINTN EntryCount;
- UINTN Index;
- if (LIST_EMPTY(&EfiFreeDescriptorList) != FALSE) {
- Entries = EfiCoreAllocatePoolPages(
- EfiBootServicesData,
- EFI_SIZE_TO_PAGES(EFI_MEMORY_EXPANSION_SIZE),
- EFI_MEMORY_EXPANSION_SIZE);
- if (Entries != NULL) {
- EntryCount = EFI_MEMORY_EXPANSION_SIZE /
- sizeof(EFI_MEMORY_MAP_ENTRY);
- for (Index = 0; Index < EntryCount; Index += 1) {
- INSERT_BEFORE(&(Entries[Index].ListEntry),
- &EfiFreeDescriptorList);
- }
- } else {
- //
- // The system just exhausted all memory, and won't do well after
- // this.
- //
- ASSERT(FALSE);
- return NULL;
- }
- }
- ASSERT(LIST_EMPTY(&EfiFreeDescriptorList) == FALSE);
- Entry = LIST_VALUE(EfiFreeDescriptorList.Next,
- EFI_MEMORY_MAP_ENTRY,
- ListEntry);
- LIST_REMOVE(&(Entry->ListEntry));
- return Entry;
- }
- VOID
- EfipDebugPrintMemoryMap (
- EFI_MEMORY_DESCRIPTOR *Map,
- UINTN MapSize,
- UINTN DescriptorSize
- )
- /*++
- Routine Description:
- This routine prints an EFI memory map out to the debugger.
- Arguments:
- Map - Supplies a pointer to the memory map.
- MapSize - Supplies the size of the map in bytes.
- DescriptorSize - Supplies the size of a single descriptor.
- Return Value:
- None.
- --*/
- {
- EFI_MEMORY_DESCRIPTOR *Descriptor;
- UINT64 Megabytes;
- UINTN Offset;
- UINT64 TotalPages;
- RtlDebugPrint("EFI Memory map at 0x%08I64x\n", Map);
- TotalPages = 0;
- Offset = 0;
- while (Offset < MapSize) {
- Descriptor = (EFI_MEMORY_DESCRIPTOR *)((VOID *)Map + Offset);
- EfipDebugPrintMemoryDescriptor(Descriptor);
- TotalPages += Descriptor->NumberOfPages;
- Offset += DescriptorSize;
- }
- Megabytes = (TotalPages << EFI_PAGE_SHIFT) / (1024ULL * 1024ULL);
- RtlDebugPrint("Total Pages: 0x%I64x (%I64dMB)\n\n", TotalPages, Megabytes);
- return;
- }
- VOID
- EfipDebugPrintMemoryDescriptor (
- EFI_MEMORY_DESCRIPTOR *Descriptor
- )
- /*++
- Routine Description:
- This routine prints an EFI memory descriptor out to the debugger.
- Arguments:
- Descriptor - Supplies a pointer to the descriptor to print.
- Return Value:
- None.
- --*/
- {
- CHAR8 *TypeString;
- switch (Descriptor->Type) {
- case EfiReservedMemoryType:
- TypeString = "ReservedMemoryType";
- break;
- case EfiLoaderCode:
- TypeString = "LoaderCode";
- break;
- case EfiLoaderData:
- TypeString = "LoaderData";
- break;
- case EfiBootServicesCode:
- TypeString = "BootServicesCode";
- break;
- case EfiBootServicesData:
- TypeString = "BootServicesData";
- break;
- case EfiRuntimeServicesCode:
- TypeString = "RuntimeServicesCode";
- break;
- case EfiRuntimeServicesData:
- TypeString = "RuntimeServicesData";
- break;
- case EfiConventionalMemory:
- TypeString = "ConventionalMemory";
- break;
- case EfiUnusableMemory:
- TypeString = "UnusableMemory";
- break;
- case EfiACPIReclaimMemory:
- TypeString = "ACPIReclaimMemory";
- break;
- case EfiACPIMemoryNVS:
- TypeString = "ACPIMemoryNVS";
- break;
- case EfiMemoryMappedIO:
- TypeString = "MemoryMappedIO";
- break;
- case EfiMemoryMappedIOPortSpace:
- TypeString = "MemoryMappedIOPortSpace";
- break;
- case EfiPalCode:
- TypeString = "PalCode";
- break;
- default:
- TypeString = "INVALID";
- break;
- }
- RtlDebugPrint("%24s PA 0x%8I64x (VA 0x%I64x) PageCount 0x%8I64x "
- "Attr 0x%x\n",
- TypeString,
- Descriptor->PhysicalStart,
- Descriptor->VirtualStart,
- Descriptor->NumberOfPages,
- Descriptor->Attribute);
- return;
- }
|