]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
EmulatorPkg/PosixFileSystem: Add NULL check on memory allocation
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
1 /** @file
2 UEFI Memory page management functions.
3
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "DxeMain.h"
10 #include "Imem.h"
11 #include "HeapGuard.h"
12
13 //
14 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
15 //
16 typedef struct {
17 EFI_PHYSICAL_ADDRESS BaseAddress;
18 EFI_PHYSICAL_ADDRESS MaximumAddress;
19 UINT64 CurrentNumberOfPages;
20 UINT64 NumberOfPages;
21 UINTN InformationIndex;
22 BOOLEAN Special;
23 BOOLEAN Runtime;
24 } EFI_MEMORY_TYPE_STATISTICS;
25
26 //
27 // MemoryMap - The current memory map
28 //
29 UINTN mMemoryMapKey = 0;
30
31 #define MAX_MAP_DEPTH 6
32
33 ///
34 /// mMapDepth - depth of new descriptor stack
35 ///
36 UINTN mMapDepth = 0;
37 ///
38 /// mMapStack - space to use as temp storage to build new map descriptors
39 ///
40 MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
41 UINTN mFreeMapStack = 0;
42 ///
43 /// This list maintain the free memory map list
44 ///
45 LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
46 BOOLEAN mMemoryTypeInformationInitialized = FALSE;
47
48 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
49 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
50 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
51 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
52 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
53 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
54 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
55 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
56 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
57 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
58 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
59 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
60 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
61 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
62 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
63 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory
64 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
65 };
66
67 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
68 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;
69
70 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
71 { EfiReservedMemoryType, 0 },
72 { EfiLoaderCode, 0 },
73 { EfiLoaderData, 0 },
74 { EfiBootServicesCode, 0 },
75 { EfiBootServicesData, 0 },
76 { EfiRuntimeServicesCode, 0 },
77 { EfiRuntimeServicesData, 0 },
78 { EfiConventionalMemory, 0 },
79 { EfiUnusableMemory, 0 },
80 { EfiACPIReclaimMemory, 0 },
81 { EfiACPIMemoryNVS, 0 },
82 { EfiMemoryMappedIO, 0 },
83 { EfiMemoryMappedIOPortSpace, 0 },
84 { EfiPalCode, 0 },
85 { EfiPersistentMemory, 0 },
86 { EfiMaxMemoryType, 0 }
87 };
88 //
89 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
90 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
91 // address assigned by DXE core.
92 //
93 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;
94
95 /**
96 Enter critical section by gaining lock on gMemoryLock.
97
98 **/
99 VOID
100 CoreAcquireMemoryLock (
101 VOID
102 )
103 {
104 CoreAcquireLock (&gMemoryLock);
105 }
106
107 /**
108 Exit critical section by releasing lock on gMemoryLock.
109
110 **/
111 VOID
112 CoreReleaseMemoryLock (
113 VOID
114 )
115 {
116 CoreReleaseLock (&gMemoryLock);
117 }
118
119 /**
120 Internal function. Removes a descriptor entry.
121
122 @param Entry The entry to remove
123
124 **/
125 VOID
126 RemoveMemoryMapEntry (
127 IN OUT MEMORY_MAP *Entry
128 )
129 {
130 RemoveEntryList (&Entry->Link);
131 Entry->Link.ForwardLink = NULL;
132
133 if (Entry->FromPages) {
134 //
135 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
136 //
137 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
138 }
139 }
140
141 /**
142 Internal function. Adds a ranges to the memory map.
143 The range must not already exist in the map.
144
145 @param Type The type of memory range to add
146 @param Start The starting address in the memory range Must be
147 paged aligned
148 @param End The last address in the range Must be the last
149 byte of a page
150 @param Attribute The attributes of the memory range to add
151
152 **/
153 VOID
154 CoreAddRange (
155 IN EFI_MEMORY_TYPE Type,
156 IN EFI_PHYSICAL_ADDRESS Start,
157 IN EFI_PHYSICAL_ADDRESS End,
158 IN UINT64 Attribute
159 )
160 {
161 LIST_ENTRY *Link;
162 MEMORY_MAP *Entry;
163
164 ASSERT ((Start & EFI_PAGE_MASK) == 0);
165 ASSERT (End > Start);
166
167 ASSERT_LOCKED (&gMemoryLock);
168
169 DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
170
171 //
172 // If memory of type EfiConventionalMemory is being added that includes the page
173 // starting at address 0, then zero the page starting at address 0. This has
174 // two benifits. It helps find NULL pointer bugs and it also maximizes
175 // compatibility with operating systems that may evaluate memory in this page
176 // for legacy data structures. If memory of any other type is added starting
177 // at address 0, then do not zero the page at address 0 because the page is being
178 // used for other purposes.
179 //
180 if ((Type == EfiConventionalMemory) && (Start == 0) && (End >= EFI_PAGE_SIZE - 1)) {
181 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
182 SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
183 }
184 }
185
186 //
187 // Memory map being altered so updated key
188 //
189 mMemoryMapKey += 1;
190
191 //
192 // UEFI 2.0 added an event group for notificaiton on memory map changes.
193 // So we need to signal this Event Group every time the memory map changes.
194 // If we are in EFI 1.10 compatability mode no event groups will be
195 // found and nothing will happen we we call this function. These events
196 // will get signaled but since a lock is held around the call to this
197 // function the notificaiton events will only be called after this function
198 // returns and the lock is released.
199 //
200 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
201
202 //
203 // Look for adjoining memory descriptor
204 //
205
206 // Two memory descriptors can only be merged if they have the same Type
207 // and the same Attribute
208 //
209
210 Link = gMemoryMap.ForwardLink;
211 while (Link != &gMemoryMap) {
212 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
213 Link = Link->ForwardLink;
214
215 if (Entry->Type != Type) {
216 continue;
217 }
218
219 if (Entry->Attribute != Attribute) {
220 continue;
221 }
222
223 if (Entry->End + 1 == Start) {
224 Start = Entry->Start;
225 RemoveMemoryMapEntry (Entry);
226 } else if (Entry->Start == End + 1) {
227 End = Entry->End;
228 RemoveMemoryMapEntry (Entry);
229 }
230 }
231
232 //
233 // Add descriptor
234 //
235
236 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
237 mMapStack[mMapDepth].FromPages = FALSE;
238 mMapStack[mMapDepth].Type = Type;
239 mMapStack[mMapDepth].Start = Start;
240 mMapStack[mMapDepth].End = End;
241 mMapStack[mMapDepth].VirtualStart = 0;
242 mMapStack[mMapDepth].Attribute = Attribute;
243 InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
244
245 mMapDepth += 1;
246 ASSERT (mMapDepth < MAX_MAP_DEPTH);
247
248 return;
249 }
250
251 /**
252 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
253 If the list is emtry, then allocate a new page to refuel the list.
254 Please Note this algorithm to allocate the memory map descriptor has a property
255 that the memory allocated for memory entries always grows, and will never really be freed
256 For example, if the current boot uses 2000 memory map entries at the maximum point, but
257 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
258 memory map entries is still allocated from EfiBootServicesMemory.
259
260
261 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
262
263 **/
264 MEMORY_MAP *
265 AllocateMemoryMapEntry (
266 VOID
267 )
268 {
269 MEMORY_MAP *FreeDescriptorEntries;
270 MEMORY_MAP *Entry;
271 UINTN Index;
272
273 if (IsListEmpty (&mFreeMemoryMapEntryList)) {
274 //
275 // The list is empty, to allocate one page to refuel the list
276 //
277 FreeDescriptorEntries = CoreAllocatePoolPages (
278 EfiBootServicesData,
279 EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),
280 DEFAULT_PAGE_ALLOCATION_GRANULARITY,
281 FALSE
282 );
283 if (FreeDescriptorEntries != NULL) {
284 //
285 // Enque the free memmory map entries into the list
286 //
287 for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof (MEMORY_MAP); Index++) {
288 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
289 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
290 }
291 } else {
292 return NULL;
293 }
294 }
295
296 //
297 // dequeue the first descriptor from the list
298 //
299 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
300 RemoveEntryList (&Entry->Link);
301
302 return Entry;
303 }
304
305 /**
306 Internal function. Moves any memory descriptors that are on the
307 temporary descriptor stack to heap.
308
309 **/
310 VOID
311 CoreFreeMemoryMapStack (
312 VOID
313 )
314 {
315 MEMORY_MAP *Entry;
316 MEMORY_MAP *Entry2;
317 LIST_ENTRY *Link2;
318
319 ASSERT_LOCKED (&gMemoryLock);
320
321 //
322 // If already freeing the map stack, then return
323 //
324 if (mFreeMapStack != 0) {
325 return;
326 }
327
328 //
329 // Move the temporary memory descriptor stack into pool
330 //
331 mFreeMapStack += 1;
332
333 while (mMapDepth != 0) {
334 //
335 // Deque an memory map entry from mFreeMemoryMapEntryList
336 //
337 Entry = AllocateMemoryMapEntry ();
338
339 ASSERT (Entry);
340
341 //
342 // Update to proper entry
343 //
344 mMapDepth -= 1;
345
346 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
347 //
348 // Move this entry to general memory
349 //
350 RemoveEntryList (&mMapStack[mMapDepth].Link);
351 mMapStack[mMapDepth].Link.ForwardLink = NULL;
352
353 CopyMem (Entry, &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
354 Entry->FromPages = TRUE;
355
356 //
357 // Find insertion location
358 //
359 for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
360 Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
361 if (Entry2->FromPages && (Entry2->Start > Entry->Start)) {
362 break;
363 }
364 }
365
366 InsertTailList (Link2, &Entry->Link);
367 } else {
368 //
369 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
370 // so here no need to move it to memory.
371 //
372 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
373 }
374 }
375
376 mFreeMapStack -= 1;
377 }
378
379 /**
380 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
381
382 **/
383 BOOLEAN
384 PromoteMemoryResource (
385 VOID
386 )
387 {
388 LIST_ENTRY *Link;
389 EFI_GCD_MAP_ENTRY *Entry;
390 BOOLEAN Promoted;
391 EFI_PHYSICAL_ADDRESS StartAddress;
392 EFI_PHYSICAL_ADDRESS EndAddress;
393 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
394
395 DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
396
397 CoreAcquireGcdMemoryLock ();
398
399 Promoted = FALSE;
400 Link = mGcdMemorySpaceMap.ForwardLink;
401 while (Link != &mGcdMemorySpaceMap) {
402 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
403
404 if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) &&
405 (Entry->EndAddress < MAX_ALLOC_ADDRESS) &&
406 ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
407 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)))
408 {
409 //
410 // Update the GCD map
411 //
412 if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
413 Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
414 } else {
415 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
416 }
417
418 Entry->Capabilities |= EFI_MEMORY_TESTED;
419 Entry->ImageHandle = gDxeCoreImageHandle;
420 Entry->DeviceHandle = NULL;
421
422 //
423 // Add to allocable system memory resource
424 //
425
426 CoreAddRange (
427 EfiConventionalMemory,
428 Entry->BaseAddress,
429 Entry->EndAddress,
430 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
431 );
432 CoreFreeMemoryMapStack ();
433
434 Promoted = TRUE;
435 }
436
437 Link = Link->ForwardLink;
438 }
439
440 CoreReleaseGcdMemoryLock ();
441
442 if (!Promoted) {
443 //
444 // If freed-memory guard is enabled, we could promote pages from
445 // guarded free pages.
446 //
447 Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);
448 if (Promoted) {
449 CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor);
450 CoreAddRange (
451 EfiConventionalMemory,
452 StartAddress,
453 EndAddress,
454 Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |
455 EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
456 );
457 }
458 }
459
460 return Promoted;
461 }
462
463 /**
464 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
465 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
466 size of boot time and runtime code.
467
468 **/
469 VOID
470 CoreLoadingFixedAddressHook (
471 VOID
472 )
473 {
474 UINT32 RuntimeCodePageNumber;
475 UINT32 BootTimeCodePageNumber;
476 EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
477 EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
478 EFI_STATUS Status;
479
480 //
481 // Make sure these 2 areas are not initialzied.
482 //
483 if (!gLoadFixedAddressCodeMemoryReady) {
484 RuntimeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
485 BootTimeCodePageNumber = PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
486 RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
487 BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
488 //
489 // Try to allocate runtime memory.
490 //
491 Status = CoreAllocatePages (
492 AllocateAddress,
493 EfiRuntimeServicesCode,
494 RuntimeCodePageNumber,
495 &RuntimeCodeBase
496 );
497 if (EFI_ERROR (Status)) {
498 //
499 // Runtime memory allocation failed
500 //
501 return;
502 }
503
504 //
505 // Try to allocate boot memory.
506 //
507 Status = CoreAllocatePages (
508 AllocateAddress,
509 EfiBootServicesCode,
510 BootTimeCodePageNumber,
511 &BootTimeCodeBase
512 );
513 if (EFI_ERROR (Status)) {
514 //
515 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
516 // new memory range is installed.
517 //
518 CoreFreePages (
519 RuntimeCodeBase,
520 RuntimeCodePageNumber
521 );
522 return;
523 }
524
525 gLoadFixedAddressCodeMemoryReady = TRUE;
526 }
527
528 return;
529 }
530
531 /**
532 Called to initialize the memory map and add descriptors to
533 the current descriptor list.
534 The first descriptor that is added must be general usable
535 memory as the addition allocates heap.
536
537 @param Type The type of memory to add
538 @param Start The starting address in the memory range Must be
539 page aligned
540 @param NumberOfPages The number of pages in the range
541 @param Attribute Attributes of the memory to add
542
543 @return None. The range is added to the memory map
544
545 **/
546 VOID
547 CoreAddMemoryDescriptor (
548 IN EFI_MEMORY_TYPE Type,
549 IN EFI_PHYSICAL_ADDRESS Start,
550 IN UINT64 NumberOfPages,
551 IN UINT64 Attribute
552 )
553 {
554 EFI_PHYSICAL_ADDRESS End;
555 EFI_STATUS Status;
556 UINTN Index;
557 UINTN FreeIndex;
558
559 if ((Start & EFI_PAGE_MASK) != 0) {
560 return;
561 }
562
563 if ((Type >= EfiMaxMemoryType) && (Type < MEMORY_TYPE_OEM_RESERVED_MIN)) {
564 return;
565 }
566
567 CoreAcquireMemoryLock ();
568 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
569 CoreAddRange (Type, Start, End, Attribute);
570 CoreFreeMemoryMapStack ();
571 CoreReleaseMemoryLock ();
572
573 ApplyMemoryProtectionPolicy (
574 EfiMaxMemoryType,
575 Type,
576 Start,
577 LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT)
578 );
579
580 //
581 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
582 //
583 if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
584 CoreLoadingFixedAddressHook ();
585 }
586
587 //
588 // Check to see if the statistics for the different memory types have already been established
589 //
590 if (mMemoryTypeInformationInitialized) {
591 return;
592 }
593
594 //
595 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
596 //
597 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
598 //
599 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
600 //
601 Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
602 if ((UINT32)Type > EfiMaxMemoryType) {
603 continue;
604 }
605
606 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
607 //
608 // Allocate pages for the current memory type from the top of available memory
609 //
610 Status = CoreAllocatePages (
611 AllocateAnyPages,
612 Type,
613 gMemoryTypeInformation[Index].NumberOfPages,
614 &mMemoryTypeStatistics[Type].BaseAddress
615 );
616 if (EFI_ERROR (Status)) {
617 //
618 // If an error occurs allocating the pages for the current memory type, then
619 // free all the pages allocates for the previous memory types and return. This
620 // operation with be retied when/if more memory is added to the system
621 //
622 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
623 //
624 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
625 //
626 Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[FreeIndex].Type);
627 if ((UINT32)Type > EfiMaxMemoryType) {
628 continue;
629 }
630
631 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
632 CoreFreePages (
633 mMemoryTypeStatistics[Type].BaseAddress,
634 gMemoryTypeInformation[FreeIndex].NumberOfPages
635 );
636 mMemoryTypeStatistics[Type].BaseAddress = 0;
637 mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;
638 }
639 }
640
641 return;
642 }
643
644 //
645 // Compute the address at the top of the current statistics
646 //
647 mMemoryTypeStatistics[Type].MaximumAddress =
648 mMemoryTypeStatistics[Type].BaseAddress +
649 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
650
651 //
652 // If the current base address is the lowest address so far, then update the default
653 // maximum address
654 //
655 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
656 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
657 }
658 }
659 }
660
661 //
662 // There was enough system memory for all the the memory types were allocated. So,
663 // those memory areas can be freed for future allocations, and all future memory
664 // allocations can occur within their respective bins
665 //
666 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
667 //
668 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
669 //
670 Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);
671 if ((UINT32)Type > EfiMaxMemoryType) {
672 continue;
673 }
674
675 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
676 CoreFreePages (
677 mMemoryTypeStatistics[Type].BaseAddress,
678 gMemoryTypeInformation[Index].NumberOfPages
679 );
680 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
681 gMemoryTypeInformation[Index].NumberOfPages = 0;
682 }
683 }
684
685 //
686 // If the number of pages reserved for a memory type is 0, then all allocations for that type
687 // should be in the default range.
688 //
689 for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
690 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
691 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
692 mMemoryTypeStatistics[Type].InformationIndex = Index;
693 }
694 }
695
696 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
697 if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
698 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
699 }
700 }
701
702 mMemoryTypeInformationInitialized = TRUE;
703 }
704
705 /**
706 Internal function. Converts a memory range to the specified type or attributes.
707 The range must exist in the memory map. Either ChangingType or
708 ChangingAttributes must be set, but not both.
709
710 @param Start The first address of the range Must be page
711 aligned
712 @param NumberOfPages The number of pages to convert
713 @param ChangingType Boolean indicating that type value should be changed
714 @param NewType The new type for the memory range
715 @param ChangingAttributes Boolean indicating that attributes value should be changed
716 @param NewAttributes The new attributes for the memory range
717
718 @retval EFI_INVALID_PARAMETER Invalid parameter
719 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
720 range or convertion not allowed.
721 @retval EFI_SUCCESS Successfully converts the memory range to the
722 specified type.
723
724 **/
725 EFI_STATUS
726 CoreConvertPagesEx (
727 IN UINT64 Start,
728 IN UINT64 NumberOfPages,
729 IN BOOLEAN ChangingType,
730 IN EFI_MEMORY_TYPE NewType,
731 IN BOOLEAN ChangingAttributes,
732 IN UINT64 NewAttributes
733 )
734 {
735 UINT64 NumberOfBytes;
736 UINT64 End;
737 UINT64 RangeEnd;
738 UINT64 Attribute;
739 EFI_MEMORY_TYPE MemType;
740 LIST_ENTRY *Link;
741 MEMORY_MAP *Entry;
742
743 Entry = NULL;
744 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
745 End = Start + NumberOfBytes - 1;
746
747 ASSERT (NumberOfPages);
748 ASSERT ((Start & EFI_PAGE_MASK) == 0);
749 ASSERT (End > Start);
750 ASSERT_LOCKED (&gMemoryLock);
751 ASSERT ((ChangingType == FALSE) || (ChangingAttributes == FALSE));
752
753 if ((NumberOfPages == 0) || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
754 return EFI_INVALID_PARAMETER;
755 }
756
757 //
758 // Convert the entire range
759 //
760
761 while (Start < End) {
762 //
763 // Find the entry that the covers the range
764 //
765 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
766 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
767
768 if ((Entry->Start <= Start) && (Entry->End > Start)) {
769 break;
770 }
771 }
772
773 if (Link == &gMemoryMap) {
774 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
775 return EFI_NOT_FOUND;
776 }
777
778 //
779 // If we are converting the type of the range from EfiConventionalMemory to
780 // another type, we have to ensure that the entire range is covered by a
781 // single entry.
782 //
783 if (ChangingType && (NewType != EfiConventionalMemory)) {
784 if (Entry->End < End) {
785 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
786 return EFI_NOT_FOUND;
787 }
788 }
789
790 //
791 // Convert range to the end, or to the end of the descriptor
792 // if that's all we've got
793 //
794 RangeEnd = End;
795
796 ASSERT (Entry != NULL);
797 if (Entry->End < End) {
798 RangeEnd = Entry->End;
799 }
800
801 if (ChangingType) {
802 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
803 }
804
805 if (ChangingAttributes) {
806 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
807 }
808
809 if (ChangingType) {
810 //
811 // Debug code - verify conversion is allowed
812 //
813 if (!((NewType == EfiConventionalMemory) ? 1 : 0) ^ ((Entry->Type == EfiConventionalMemory) ? 1 : 0)) {
814 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
815 if (Entry->Type == EfiConventionalMemory) {
816 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
817 } else {
818 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
819 }
820
821 return EFI_NOT_FOUND;
822 }
823
824 //
825 // Update counters for the number of pages allocated to each memory type
826 //
827 if ((UINT32)Entry->Type < EfiMaxMemoryType) {
828 if (((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress) && (Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress)) ||
829 ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))
830 {
831 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
832 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
833 } else {
834 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
835 }
836 }
837 }
838
839 if ((UINT32)NewType < EfiMaxMemoryType) {
840 if (((Start >= mMemoryTypeStatistics[NewType].BaseAddress) && (Start <= mMemoryTypeStatistics[NewType].MaximumAddress)) ||
841 ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))
842 {
843 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
844 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
845 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
846 }
847 }
848 }
849 }
850
851 //
852 // Pull range out of descriptor
853 //
854 if (Entry->Start == Start) {
855 //
856 // Clip start
857 //
858 Entry->Start = RangeEnd + 1;
859 } else if (Entry->End == RangeEnd) {
860 //
861 // Clip end
862 //
863 Entry->End = Start - 1;
864 } else {
865 //
866 // Pull it out of the center, clip current
867 //
868
869 //
870 // Add a new one
871 //
872 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
873 mMapStack[mMapDepth].FromPages = FALSE;
874 mMapStack[mMapDepth].Type = Entry->Type;
875 mMapStack[mMapDepth].Start = RangeEnd+1;
876 mMapStack[mMapDepth].End = Entry->End;
877
878 //
879 // Inherit Attribute from the Memory Descriptor that is being clipped
880 //
881 mMapStack[mMapDepth].Attribute = Entry->Attribute;
882
883 Entry->End = Start - 1;
884 ASSERT (Entry->Start < Entry->End);
885
886 Entry = &mMapStack[mMapDepth];
887 InsertTailList (&gMemoryMap, &Entry->Link);
888
889 mMapDepth += 1;
890 ASSERT (mMapDepth < MAX_MAP_DEPTH);
891 }
892
893 //
894 // The new range inherits the same Attribute as the Entry
895 // it is being cut out of unless attributes are being changed
896 //
897 if (ChangingType) {
898 Attribute = Entry->Attribute;
899 MemType = NewType;
900 } else {
901 Attribute = NewAttributes;
902 MemType = Entry->Type;
903 }
904
905 //
906 // If the descriptor is empty, then remove it from the map
907 //
908 if (Entry->Start == Entry->End + 1) {
909 RemoveMemoryMapEntry (Entry);
910 Entry = NULL;
911 }
912
913 //
914 // Add our new range in. Don't do this for freed pages if freed-memory
915 // guard is enabled.
916 //
917 if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
918 !ChangingType ||
919 (MemType != EfiConventionalMemory))
920 {
921 CoreAddRange (MemType, Start, RangeEnd, Attribute);
922 }
923
924 if (ChangingType && (MemType == EfiConventionalMemory)) {
925 //
926 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
927 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
928 // that the page starting at address 0 is always filled with zeros.
929 //
930 if (Start == 0) {
931 if (RangeEnd > EFI_PAGE_SIZE) {
932 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)EFI_PAGE_SIZE, (UINTN)(RangeEnd - EFI_PAGE_SIZE + 1));
933 }
934 } else {
935 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Start, (UINTN)(RangeEnd - Start + 1));
936 }
937 }
938
939 //
940 // Move any map descriptor stack to general pool
941 //
942 CoreFreeMemoryMapStack ();
943
944 //
945 // Bump the starting address, and convert the next range
946 //
947 Start = RangeEnd + 1;
948 }
949
950 //
951 // Converted the whole range, done
952 //
953
954 return EFI_SUCCESS;
955 }
956
957 /**
958 Internal function. Converts a memory range to the specified type.
959 The range must exist in the memory map.
960
961 @param Start The first address of the range Must be page
962 aligned
963 @param NumberOfPages The number of pages to convert
964 @param NewType The new type for the memory range
965
966 @retval EFI_INVALID_PARAMETER Invalid parameter
967 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
968 range or convertion not allowed.
969 @retval EFI_SUCCESS Successfully converts the memory range to the
970 specified type.
971
972 **/
973 EFI_STATUS
974 CoreConvertPages (
975 IN UINT64 Start,
976 IN UINT64 NumberOfPages,
977 IN EFI_MEMORY_TYPE NewType
978 )
979 {
980 return CoreConvertPagesEx (Start, NumberOfPages, TRUE, NewType, FALSE, 0);
981 }
982
983 /**
984 Internal function. Converts a memory range to use new attributes.
985
986 @param Start The first address of the range Must be page
987 aligned
988 @param NumberOfPages The number of pages to convert
989 @param NewAttributes The new attributes value for the range.
990
991 **/
992 VOID
993 CoreUpdateMemoryAttributes (
994 IN EFI_PHYSICAL_ADDRESS Start,
995 IN UINT64 NumberOfPages,
996 IN UINT64 NewAttributes
997 )
998 {
999 CoreAcquireMemoryLock ();
1000
1001 //
1002 // Update the attributes to the new value
1003 //
1004 CoreConvertPagesEx (Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
1005
1006 CoreReleaseMemoryLock ();
1007 }
1008
1009 /**
1010 Internal function. Finds a consecutive free page range below
1011 the requested address.
1012
1013 @param MaxAddress The address that the range must be below
1014 @param MinAddress The address that the range must be above
1015 @param NumberOfPages Number of pages needed
1016 @param NewType The type of memory the range is going to be
1017 turned into
1018 @param Alignment Bits to align with
1019 @param NeedGuard Flag to indicate Guard page is needed or not
1020
1021 @return The base address of the range, or 0 if the range was not found
1022
1023 **/
1024 UINT64
1025 CoreFindFreePagesI (
1026 IN UINT64 MaxAddress,
1027 IN UINT64 MinAddress,
1028 IN UINT64 NumberOfPages,
1029 IN EFI_MEMORY_TYPE NewType,
1030 IN UINTN Alignment,
1031 IN BOOLEAN NeedGuard
1032 )
1033 {
1034 UINT64 NumberOfBytes;
1035 UINT64 Target;
1036 UINT64 DescStart;
1037 UINT64 DescEnd;
1038 UINT64 DescNumberOfBytes;
1039 LIST_ENTRY *Link;
1040 MEMORY_MAP *Entry;
1041
1042 if ((MaxAddress < EFI_PAGE_MASK) || (NumberOfPages == 0)) {
1043 return 0;
1044 }
1045
1046 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
1047 //
1048 // If MaxAddress is not aligned to the end of a page
1049 //
1050
1051 //
1052 // Change MaxAddress to be 1 page lower
1053 //
1054 MaxAddress -= (EFI_PAGE_MASK + 1);
1055
1056 //
1057 // Set MaxAddress to a page boundary
1058 //
1059 MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
1060
1061 //
1062 // Set MaxAddress to end of the page
1063 //
1064 MaxAddress |= EFI_PAGE_MASK;
1065 }
1066
1067 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1068 Target = 0;
1069
1070 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1071 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1072
1073 //
1074 // If it's not a free entry, don't bother with it
1075 //
1076 if (Entry->Type != EfiConventionalMemory) {
1077 continue;
1078 }
1079
1080 DescStart = Entry->Start;
1081 DescEnd = Entry->End;
1082
1083 //
1084 // If desc is past max allowed address or below min allowed address, skip it
1085 //
1086 if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
1087 continue;
1088 }
1089
1090 //
1091 // If desc ends past max allowed address, clip the end
1092 //
1093 if (DescEnd >= MaxAddress) {
1094 DescEnd = MaxAddress;
1095 }
1096
1097 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
1098
1099 // Skip if DescEnd is less than DescStart after alignment clipping
1100 if (DescEnd < DescStart) {
1101 continue;
1102 }
1103
1104 //
1105 // Compute the number of bytes we can used from this
1106 // descriptor, and see it's enough to satisfy the request
1107 //
1108 DescNumberOfBytes = DescEnd - DescStart + 1;
1109
1110 if (DescNumberOfBytes >= NumberOfBytes) {
1111 //
1112 // If the start of the allocated range is below the min address allowed, skip it
1113 //
1114 if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
1115 continue;
1116 }
1117
1118 //
1119 // If this is the best match so far remember it
1120 //
1121 if (DescEnd > Target) {
1122 if (NeedGuard) {
1123 DescEnd = AdjustMemoryS (
1124 DescEnd + 1 - DescNumberOfBytes,
1125 DescNumberOfBytes,
1126 NumberOfBytes
1127 );
1128 if (DescEnd == 0) {
1129 continue;
1130 }
1131 }
1132
1133 Target = DescEnd;
1134 }
1135 }
1136 }
1137
1138 //
1139 // If this is a grow down, adjust target to be the allocation base
1140 //
1141 Target -= NumberOfBytes - 1;
1142
1143 //
1144 // If we didn't find a match, return 0
1145 //
1146 if ((Target & EFI_PAGE_MASK) != 0) {
1147 return 0;
1148 }
1149
1150 return Target;
1151 }
1152
1153 /**
1154 Internal function. Finds a consecutive free page range below
1155 the requested address
1156
1157 @param MaxAddress The address that the range must be below
1158 @param NoPages Number of pages needed
1159 @param NewType The type of memory the range is going to be
1160 turned into
1161 @param Alignment Bits to align with
1162 @param NeedGuard Flag to indicate Guard page is needed or not
1163
1164 @return The base address of the range, or 0 if the range was not found.
1165
1166 **/
1167 UINT64
1168 FindFreePages (
1169 IN UINT64 MaxAddress,
1170 IN UINT64 NoPages,
1171 IN EFI_MEMORY_TYPE NewType,
1172 IN UINTN Alignment,
1173 IN BOOLEAN NeedGuard
1174 )
1175 {
1176 UINT64 Start;
1177
1178 //
1179 // Attempt to find free pages in the preferred bin based on the requested memory type
1180 //
1181 if (((UINT32)NewType < EfiMaxMemoryType) && (MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress)) {
1182 Start = CoreFindFreePagesI (
1183 mMemoryTypeStatistics[NewType].MaximumAddress,
1184 mMemoryTypeStatistics[NewType].BaseAddress,
1185 NoPages,
1186 NewType,
1187 Alignment,
1188 NeedGuard
1189 );
1190 if (Start != 0) {
1191 return Start;
1192 }
1193 }
1194
1195 //
1196 // Attempt to find free pages in the default allocation bin
1197 //
1198 if (MaxAddress >= mDefaultMaximumAddress) {
1199 Start = CoreFindFreePagesI (
1200 mDefaultMaximumAddress,
1201 0,
1202 NoPages,
1203 NewType,
1204 Alignment,
1205 NeedGuard
1206 );
1207 if (Start != 0) {
1208 if (Start < mDefaultBaseAddress) {
1209 mDefaultBaseAddress = Start;
1210 }
1211
1212 return Start;
1213 }
1214 }
1215
1216 //
1217 // The allocation did not succeed in any of the prefered bins even after
1218 // promoting resources. Attempt to find free pages anywhere is the requested
1219 // address range. If this allocation fails, then there are not enough
1220 // resources anywhere to satisfy the request.
1221 //
1222 Start = CoreFindFreePagesI (
1223 MaxAddress,
1224 0,
1225 NoPages,
1226 NewType,
1227 Alignment,
1228 NeedGuard
1229 );
1230 if (Start != 0) {
1231 return Start;
1232 }
1233
1234 //
1235 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1236 //
1237 if (!PromoteMemoryResource ()) {
1238 return 0;
1239 }
1240
1241 //
1242 // If any memory resources were promoted, then re-attempt the allocation
1243 //
1244 return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
1245 }
1246
1247 /**
1248 Allocates pages from the memory map.
1249
1250 @param Type The type of allocation to perform
1251 @param MemoryType The type of memory to turn the allocated pages
1252 into
1253 @param NumberOfPages The number of pages to allocate
1254 @param Memory A pointer to receive the base allocated memory
1255 address
1256 @param NeedGuard Flag to indicate Guard page is needed or not
1257
1258 @return Status. On success, Memory is filled in with the base address allocated
1259 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1260 spec.
1261 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1262 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1263 @retval EFI_SUCCESS Pages successfully allocated.
1264
1265 **/
1266 EFI_STATUS
1267 EFIAPI
1268 CoreInternalAllocatePages (
1269 IN EFI_ALLOCATE_TYPE Type,
1270 IN EFI_MEMORY_TYPE MemoryType,
1271 IN UINTN NumberOfPages,
1272 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
1273 IN BOOLEAN NeedGuard
1274 )
1275 {
1276 EFI_STATUS Status;
1277 UINT64 Start;
1278 UINT64 NumberOfBytes;
1279 UINT64 End;
1280 UINT64 MaxAddress;
1281 UINTN Alignment;
1282 EFI_MEMORY_TYPE CheckType;
1283
1284 if ((UINT32)Type >= MaxAllocateType) {
1285 return EFI_INVALID_PARAMETER;
1286 }
1287
1288 if (((MemoryType >= EfiMaxMemoryType) && (MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||
1289 (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory))
1290 {
1291 return EFI_INVALID_PARAMETER;
1292 }
1293
1294 if (Memory == NULL) {
1295 return EFI_INVALID_PARAMETER;
1296 }
1297
1298 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1299
1300 if ((MemoryType == EfiACPIReclaimMemory) ||
1301 (MemoryType == EfiACPIMemoryNVS) ||
1302 (MemoryType == EfiRuntimeServicesCode) ||
1303 (MemoryType == EfiRuntimeServicesData))
1304 {
1305 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1306 }
1307
1308 if (Type == AllocateAddress) {
1309 if ((*Memory & (Alignment - 1)) != 0) {
1310 return EFI_NOT_FOUND;
1311 }
1312 }
1313
1314 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1315 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1316
1317 //
1318 // If this is for below a particular address, then
1319 //
1320 Start = *Memory;
1321
1322 //
1323 // The max address is the max natively addressable address for the processor
1324 //
1325 MaxAddress = MAX_ALLOC_ADDRESS;
1326
1327 //
1328 // Check for Type AllocateAddress,
1329 // if NumberOfPages is 0 or
1330 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1331 // if (Start + NumberOfBytes) rolls over 0 or
1332 // if Start is above MAX_ALLOC_ADDRESS or
1333 // if End is above MAX_ALLOC_ADDRESS,
1334 // if Start..End overlaps any tracked MemoryTypeStatistics range
1335 // return EFI_NOT_FOUND.
1336 //
1337 if (Type == AllocateAddress) {
1338 if ((NumberOfPages == 0) ||
1339 (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT)))
1340 {
1341 return EFI_NOT_FOUND;
1342 }
1343
1344 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1345 End = Start + NumberOfBytes - 1;
1346
1347 if ((Start >= End) ||
1348 (Start > MaxAddress) ||
1349 (End > MaxAddress))
1350 {
1351 return EFI_NOT_FOUND;
1352 }
1353
1354 //
1355 // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of
1356 // AllocatePage request the exact physical address if it is not used. The existing code
1357 // will allow this request even in 'special' pages. The problem with this is that the
1358 // reason to have 'special' pages for OS hibernate/resume is defeated as memory is
1359 // fragmented.
1360 //
1361
1362 for (CheckType = (EFI_MEMORY_TYPE)0; CheckType < EfiMaxMemoryType; CheckType++) {
1363 if ((MemoryType != CheckType) &&
1364 mMemoryTypeStatistics[CheckType].Special &&
1365 (mMemoryTypeStatistics[CheckType].NumberOfPages > 0))
1366 {
1367 if ((Start >= mMemoryTypeStatistics[CheckType].BaseAddress) &&
1368 (Start <= mMemoryTypeStatistics[CheckType].MaximumAddress))
1369 {
1370 return EFI_NOT_FOUND;
1371 }
1372
1373 if ((End >= mMemoryTypeStatistics[CheckType].BaseAddress) &&
1374 (End <= mMemoryTypeStatistics[CheckType].MaximumAddress))
1375 {
1376 return EFI_NOT_FOUND;
1377 }
1378
1379 if ((Start < mMemoryTypeStatistics[CheckType].BaseAddress) &&
1380 (End > mMemoryTypeStatistics[CheckType].MaximumAddress))
1381 {
1382 return EFI_NOT_FOUND;
1383 }
1384 }
1385 }
1386 }
1387
1388 if (Type == AllocateMaxAddress) {
1389 MaxAddress = Start;
1390 }
1391
1392 CoreAcquireMemoryLock ();
1393
1394 //
1395 // If not a specific address, then find an address to allocate
1396 //
1397 if (Type != AllocateAddress) {
1398 Start = FindFreePages (
1399 MaxAddress,
1400 NumberOfPages,
1401 MemoryType,
1402 Alignment,
1403 NeedGuard
1404 );
1405 if (Start == 0) {
1406 Status = EFI_OUT_OF_RESOURCES;
1407 goto Done;
1408 }
1409 }
1410
1411 //
1412 // Convert pages from FreeMemory to the requested type
1413 //
1414 if (NeedGuard) {
1415 Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);
1416 } else {
1417 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
1418 }
1419
1420 Done:
1421 CoreReleaseMemoryLock ();
1422
1423 if (!EFI_ERROR (Status)) {
1424 if (NeedGuard) {
1425 SetGuardForMemory (Start, NumberOfPages);
1426 }
1427
1428 *Memory = Start;
1429 }
1430
1431 return Status;
1432 }
1433
1434 /**
1435 Allocates pages from the memory map.
1436
1437 @param Type The type of allocation to perform
1438 @param MemoryType The type of memory to turn the allocated pages
1439 into
1440 @param NumberOfPages The number of pages to allocate
1441 @param Memory A pointer to receive the base allocated memory
1442 address
1443
1444 @return Status. On success, Memory is filled in with the base address allocated
1445 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1446 spec.
1447 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1448 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1449 @retval EFI_SUCCESS Pages successfully allocated.
1450
1451 **/
1452 EFI_STATUS
1453 EFIAPI
1454 CoreAllocatePages (
1455 IN EFI_ALLOCATE_TYPE Type,
1456 IN EFI_MEMORY_TYPE MemoryType,
1457 IN UINTN NumberOfPages,
1458 OUT EFI_PHYSICAL_ADDRESS *Memory
1459 )
1460 {
1461 EFI_STATUS Status;
1462 BOOLEAN NeedGuard;
1463
1464 NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
1465 Status = CoreInternalAllocatePages (
1466 Type,
1467 MemoryType,
1468 NumberOfPages,
1469 Memory,
1470 NeedGuard
1471 );
1472 if (!EFI_ERROR (Status)) {
1473 CoreUpdateProfile (
1474 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
1475 MemoryProfileActionAllocatePages,
1476 MemoryType,
1477 EFI_PAGES_TO_SIZE (NumberOfPages),
1478 (VOID *)(UINTN)*Memory,
1479 NULL
1480 );
1481 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1482 ApplyMemoryProtectionPolicy (
1483 EfiConventionalMemory,
1484 MemoryType,
1485 *Memory,
1486 EFI_PAGES_TO_SIZE (NumberOfPages)
1487 );
1488 }
1489
1490 return Status;
1491 }
1492
1493 /**
1494 Frees previous allocated pages.
1495
1496 @param Memory Base address of memory being freed
1497 @param NumberOfPages The number of pages to free
1498 @param MemoryType Pointer to memory type
1499
1500 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1501 @retval EFI_INVALID_PARAMETER Address not aligned
1502 @return EFI_SUCCESS -Pages successfully freed.
1503
1504 **/
1505 EFI_STATUS
1506 EFIAPI
1507 CoreInternalFreePages (
1508 IN EFI_PHYSICAL_ADDRESS Memory,
1509 IN UINTN NumberOfPages,
1510 OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
1511 )
1512 {
1513 EFI_STATUS Status;
1514 LIST_ENTRY *Link;
1515 MEMORY_MAP *Entry;
1516 UINTN Alignment;
1517 BOOLEAN IsGuarded;
1518
1519 //
1520 // Free the range
1521 //
1522 CoreAcquireMemoryLock ();
1523
1524 //
1525 // Find the entry that the covers the range
1526 //
1527 IsGuarded = FALSE;
1528 Entry = NULL;
1529 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1530 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1531 if ((Entry->Start <= Memory) && (Entry->End > Memory)) {
1532 break;
1533 }
1534 }
1535
1536 if (Link == &gMemoryMap) {
1537 Status = EFI_NOT_FOUND;
1538 goto Done;
1539 }
1540
1541 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1542
1543 ASSERT (Entry != NULL);
1544 if ((Entry->Type == EfiACPIReclaimMemory) ||
1545 (Entry->Type == EfiACPIMemoryNVS) ||
1546 (Entry->Type == EfiRuntimeServicesCode) ||
1547 (Entry->Type == EfiRuntimeServicesData))
1548 {
1549 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1550 }
1551
1552 if ((Memory & (Alignment - 1)) != 0) {
1553 Status = EFI_INVALID_PARAMETER;
1554 goto Done;
1555 }
1556
1557 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1558 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1559
1560 if (MemoryType != NULL) {
1561 *MemoryType = Entry->Type;
1562 }
1563
1564 IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
1565 IsMemoryGuarded (Memory);
1566 if (IsGuarded) {
1567 Status = CoreConvertPagesWithGuard (
1568 Memory,
1569 NumberOfPages,
1570 EfiConventionalMemory
1571 );
1572 } else {
1573 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1574 }
1575
1576 Done:
1577 CoreReleaseMemoryLock ();
1578 return Status;
1579 }
1580
1581 /**
1582 Frees previous allocated pages.
1583
1584 @param Memory Base address of memory being freed
1585 @param NumberOfPages The number of pages to free
1586
1587 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1588 @retval EFI_INVALID_PARAMETER Address not aligned
1589 @return EFI_SUCCESS -Pages successfully freed.
1590
1591 **/
1592 EFI_STATUS
1593 EFIAPI
1594 CoreFreePages (
1595 IN EFI_PHYSICAL_ADDRESS Memory,
1596 IN UINTN NumberOfPages
1597 )
1598 {
1599 EFI_STATUS Status;
1600 EFI_MEMORY_TYPE MemoryType;
1601
1602 Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
1603 if (!EFI_ERROR (Status)) {
1604 GuardFreedPagesChecked (Memory, NumberOfPages);
1605 CoreUpdateProfile (
1606 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
1607 MemoryProfileActionFreePages,
1608 MemoryType,
1609 EFI_PAGES_TO_SIZE (NumberOfPages),
1610 (VOID *)(UINTN)Memory,
1611 NULL
1612 );
1613 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1614 ApplyMemoryProtectionPolicy (
1615 MemoryType,
1616 EfiConventionalMemory,
1617 Memory,
1618 EFI_PAGES_TO_SIZE (NumberOfPages)
1619 );
1620 }
1621
1622 return Status;
1623 }
1624
1625 /**
1626 This function checks to see if the last memory map descriptor in a memory map
1627 can be merged with any of the other memory map descriptors in a memorymap.
1628 Memory descriptors may be merged if they are adjacent and have the same type
1629 and attributes.
1630
1631 @param MemoryMap A pointer to the start of the memory map.
1632 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1633 @param DescriptorSize The size, in bytes, of an individual
1634 EFI_MEMORY_DESCRIPTOR.
1635
1636 @return A pointer to the next available descriptor in MemoryMap
1637
1638 **/
1639 EFI_MEMORY_DESCRIPTOR *
1640 MergeMemoryMapDescriptor (
1641 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
1642 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
1643 IN UINTN DescriptorSize
1644 )
1645 {
1646 //
1647 // Traverse the array of descriptors in MemoryMap
1648 //
1649 for ( ; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1650 //
1651 // Check to see if the Type fields are identical.
1652 //
1653 if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1654 continue;
1655 }
1656
1657 //
1658 // Check to see if the Attribute fields are identical.
1659 //
1660 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1661 continue;
1662 }
1663
1664 //
1665 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1666 //
1667 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1668 //
1669 // Merge MemoryMapDescriptor into MemoryMap
1670 //
1671 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1672
1673 //
1674 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1675 //
1676 return MemoryMapDescriptor;
1677 }
1678
1679 //
1680 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1681 //
1682 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1683 //
1684 // Merge MemoryMapDescriptor into MemoryMap
1685 //
1686 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
1687 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
1688 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1689
1690 //
1691 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1692 //
1693 return MemoryMapDescriptor;
1694 }
1695 }
1696
1697 //
1698 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1699 //
1700 // Return the slot immediately after MemoryMapDescriptor as the next available
1701 // slot in the MemoryMap array
1702 //
1703 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1704 }
1705
1706 /**
1707 This function returns a copy of the current memory map. The map is an array of
1708 memory descriptors, each of which describes a contiguous block of memory.
1709
1710 @param MemoryMapSize A pointer to the size, in bytes, of the
1711 MemoryMap buffer. On input, this is the size of
1712 the buffer allocated by the caller. On output,
1713 it is the size of the buffer returned by the
1714 firmware if the buffer was large enough, or the
1715 size of the buffer needed to contain the map if
1716 the buffer was too small.
1717 @param MemoryMap A pointer to the buffer in which firmware places
1718 the current memory map.
1719 @param MapKey A pointer to the location in which firmware
1720 returns the key for the current memory map.
1721 @param DescriptorSize A pointer to the location in which firmware
1722 returns the size, in bytes, of an individual
1723 EFI_MEMORY_DESCRIPTOR.
1724 @param DescriptorVersion A pointer to the location in which firmware
1725 returns the version number associated with the
1726 EFI_MEMORY_DESCRIPTOR.
1727
1728 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1729 buffer.
1730 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1731 buffer size needed to hold the memory map is
1732 returned in MemoryMapSize.
1733 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1734
1735 **/
1736 EFI_STATUS
1737 EFIAPI
1738 CoreGetMemoryMap (
1739 IN OUT UINTN *MemoryMapSize,
1740 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1741 OUT UINTN *MapKey,
1742 OUT UINTN *DescriptorSize,
1743 OUT UINT32 *DescriptorVersion
1744 )
1745 {
1746 EFI_STATUS Status;
1747 UINTN Size;
1748 UINTN BufferSize;
1749 UINTN NumberOfEntries;
1750 LIST_ENTRY *Link;
1751 MEMORY_MAP *Entry;
1752 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1753 EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
1754 EFI_MEMORY_TYPE Type;
1755 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1756 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
1757
1758 //
1759 // Make sure the parameters are valid
1760 //
1761 if (MemoryMapSize == NULL) {
1762 return EFI_INVALID_PARAMETER;
1763 }
1764
1765 CoreAcquireGcdMemoryLock ();
1766
1767 //
1768 // Count the number of Reserved and runtime MMIO entries
1769 // And, count the number of Persistent entries.
1770 //
1771 NumberOfEntries = 0;
1772 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1773 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1774 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
1775 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1776 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1777 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
1778 {
1779 NumberOfEntries++;
1780 }
1781 }
1782
1783 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1784
1785 //
1786 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1787 // prevent people from having pointer math bugs in their code.
1788 // now you have to use *DescriptorSize to make things work.
1789 //
1790 Size += sizeof (UINT64) - (Size % sizeof (UINT64));
1791
1792 if (DescriptorSize != NULL) {
1793 *DescriptorSize = Size;
1794 }
1795
1796 if (DescriptorVersion != NULL) {
1797 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1798 }
1799
1800 CoreAcquireMemoryLock ();
1801
1802 //
1803 // Compute the buffer size needed to fit the entire map
1804 //
1805 BufferSize = Size * NumberOfEntries;
1806 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1807 BufferSize += Size;
1808 }
1809
1810 if (*MemoryMapSize < BufferSize) {
1811 Status = EFI_BUFFER_TOO_SMALL;
1812 goto Done;
1813 }
1814
1815 if (MemoryMap == NULL) {
1816 Status = EFI_INVALID_PARAMETER;
1817 goto Done;
1818 }
1819
1820 //
1821 // Build the map
1822 //
1823 ZeroMem (MemoryMap, BufferSize);
1824 MemoryMapStart = MemoryMap;
1825 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1826 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1827 ASSERT (Entry->VirtualStart == 0);
1828
1829 //
1830 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1831 //
1832 MemoryMap->Type = Entry->Type;
1833 MemoryMap->PhysicalStart = Entry->Start;
1834 MemoryMap->VirtualStart = Entry->VirtualStart;
1835 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1836 //
1837 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1838 // memory type bin and needs to be converted to the same memory type as the rest of the
1839 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1840 // improves the chances for a successful S4 resume in the presence of minor page allocation
1841 // differences across reboots.
1842 //
1843 if (MemoryMap->Type == EfiConventionalMemory) {
1844 for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
1845 if (mMemoryTypeStatistics[Type].Special &&
1846 (mMemoryTypeStatistics[Type].NumberOfPages > 0) &&
1847 (Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress) &&
1848 (Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress))
1849 {
1850 MemoryMap->Type = Type;
1851 }
1852 }
1853 }
1854
1855 MemoryMap->Attribute = Entry->Attribute;
1856 if (MemoryMap->Type < EfiMaxMemoryType) {
1857 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1858 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1859 }
1860 }
1861
1862 //
1863 // Check to see if the new Memory Map Descriptor can be merged with an
1864 // existing descriptor if they are adjacent and have the same attributes
1865 //
1866 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1867 }
1868
1869 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1870 GcdMapEntry = NULL;
1871 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1872 if (Link != &mGcdMemorySpaceMap) {
1873 //
1874 // Merge adjacent same type and attribute GCD memory range
1875 //
1876 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1877
1878 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1879 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1880 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1881 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType))
1882 {
1883 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
1884 continue;
1885 }
1886 }
1887
1888 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1889 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1890 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
1891 {
1892 //
1893 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1894 // it will be recorded as page PhysicalStart and NumberOfPages.
1895 //
1896 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1897 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1898
1899 //
1900 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1901 //
1902 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1903 MemoryMap->VirtualStart = 0;
1904 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1905 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1906 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
1907
1908 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1909 MemoryMap->Type = EfiReservedMemoryType;
1910 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1911 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1912 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1913 } else {
1914 MemoryMap->Type = EfiMemoryMappedIO;
1915 }
1916 }
1917
1918 //
1919 // Check to see if the new Memory Map Descriptor can be merged with an
1920 // existing descriptor if they are adjacent and have the same attributes
1921 //
1922 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1923 }
1924
1925 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
1926 //
1927 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1928 // it will be recorded as page PhysicalStart and NumberOfPages.
1929 //
1930 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1931 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1932
1933 //
1934 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1935 //
1936 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1937 MemoryMap->VirtualStart = 0;
1938 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1939 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1940 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
1941 MemoryMap->Type = EfiPersistentMemory;
1942
1943 //
1944 // Check to see if the new Memory Map Descriptor can be merged with an
1945 // existing descriptor if they are adjacent and have the same attributes
1946 //
1947 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1948 }
1949
1950 if (Link == &mGcdMemorySpaceMap) {
1951 //
1952 // break loop when arrive at head.
1953 //
1954 break;
1955 }
1956
1957 if (GcdMapEntry != NULL) {
1958 //
1959 // Copy new GCD map entry for the following GCD range merge
1960 //
1961 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1962 }
1963 }
1964
1965 //
1966 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1967 //
1968 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1969
1970 //
1971 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1972 // set attributes and change memory paging attribute accordingly.
1973 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1974 // value from Capabilities in GCD memory map. This might cause
1975 // boot problems. Clearing all page-access permission related
1976 // capabilities can workaround it. Following code is supposed to
1977 // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
1978 // is clarified in UEFI spec and adopted by both EDK-II Core and
1979 // all supported OSs.
1980 //
1981 MemoryMapEnd = MemoryMap;
1982 MemoryMap = MemoryMapStart;
1983 while (MemoryMap < MemoryMapEnd) {
1984 MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;
1985 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
1986 }
1987
1988 MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
1989 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
1990
1991 Status = EFI_SUCCESS;
1992
1993 Done:
1994 //
1995 // Update the map key finally
1996 //
1997 if (MapKey != NULL) {
1998 *MapKey = mMemoryMapKey;
1999 }
2000
2001 CoreReleaseMemoryLock ();
2002
2003 CoreReleaseGcdMemoryLock ();
2004
2005 *MemoryMapSize = BufferSize;
2006
2007 DEBUG_CODE (
2008 DumpGuardedMemoryBitmap ();
2009 );
2010
2011 return Status;
2012 }
2013
2014 /**
2015 Internal function. Used by the pool functions to allocate pages
2016 to back pool allocation requests.
2017
2018 @param PoolType The type of memory for the new pool pages
2019 @param NumberOfPages No of pages to allocate
2020 @param Alignment Bits to align.
2021 @param NeedGuard Flag to indicate Guard page is needed or not
2022
2023 @return The allocated memory, or NULL
2024
2025 **/
2026 VOID *
2027 CoreAllocatePoolPages (
2028 IN EFI_MEMORY_TYPE PoolType,
2029 IN UINTN NumberOfPages,
2030 IN UINTN Alignment,
2031 IN BOOLEAN NeedGuard
2032 )
2033 {
2034 UINT64 Start;
2035
2036 //
2037 // Find the pages to convert
2038 //
2039 Start = FindFreePages (
2040 MAX_ALLOC_ADDRESS,
2041 NumberOfPages,
2042 PoolType,
2043 Alignment,
2044 NeedGuard
2045 );
2046
2047 //
2048 // Convert it to boot services data
2049 //
2050 if (Start == 0) {
2051 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
2052 } else {
2053 if (NeedGuard) {
2054 CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
2055 } else {
2056 CoreConvertPages (Start, NumberOfPages, PoolType);
2057 }
2058 }
2059
2060 return (VOID *)(UINTN)Start;
2061 }
2062
2063 /**
2064 Internal function. Frees pool pages allocated via AllocatePoolPages ()
2065
2066 @param Memory The base address to free
2067 @param NumberOfPages The number of pages to free
2068
2069 **/
2070 VOID
2071 CoreFreePoolPages (
2072 IN EFI_PHYSICAL_ADDRESS Memory,
2073 IN UINTN NumberOfPages
2074 )
2075 {
2076 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
2077 }
2078
2079 /**
2080 Make sure the memory map is following all the construction rules,
2081 it is the last time to check memory map error before exit boot services.
2082
2083 @param MapKey Memory map key
2084
2085 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2086 rules.
2087 @retval EFI_SUCCESS Valid memory map.
2088
2089 **/
2090 EFI_STATUS
2091 CoreTerminateMemoryMap (
2092 IN UINTN MapKey
2093 )
2094 {
2095 EFI_STATUS Status;
2096 LIST_ENTRY *Link;
2097 MEMORY_MAP *Entry;
2098
2099 Status = EFI_SUCCESS;
2100
2101 CoreAcquireMemoryLock ();
2102
2103 if (MapKey == mMemoryMapKey) {
2104 //
2105 // Make sure the memory map is following all the construction rules
2106 // This is the last chance we will be able to display any messages on
2107 // the console devices.
2108 //
2109
2110 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
2111 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
2112 if (Entry->Type < EfiMaxMemoryType) {
2113 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
2114 ASSERT (Entry->Type != EfiACPIReclaimMemory);
2115 ASSERT (Entry->Type != EfiACPIMemoryNVS);
2116 if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2117 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2118 Status = EFI_INVALID_PARAMETER;
2119 goto Done;
2120 }
2121
2122 if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2123 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2124 Status = EFI_INVALID_PARAMETER;
2125 goto Done;
2126 }
2127 }
2128 }
2129 }
2130
2131 //
2132 // The map key they gave us matches what we expect. Fall through and
2133 // return success. In an ideal world we would clear out all of
2134 // EfiBootServicesCode and EfiBootServicesData. However this function
2135 // is not the last one called by ExitBootServices(), so we have to
2136 // preserve the memory contents.
2137 //
2138 } else {
2139 Status = EFI_INVALID_PARAMETER;
2140 }
2141
2142 Done:
2143 CoreReleaseMemoryLock ();
2144
2145 return Status;
2146 }