]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
cc0b90ac0df53e35b2c58db57e55c4a51cb65c1c
[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 if (EFI_ERROR (Status)) {
1421 //
1422 // If requested memory region is unavailable it may be untested memory
1423 // Attempt to promote memory resources, then re-attempt the allocation
1424 //
1425 if (PromoteMemoryResource ()) {
1426 if (NeedGuard) {
1427 Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);
1428 } else {
1429 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
1430 }
1431 }
1432 }
1433
1434 Done:
1435 CoreReleaseMemoryLock ();
1436
1437 if (!EFI_ERROR (Status)) {
1438 if (NeedGuard) {
1439 SetGuardForMemory (Start, NumberOfPages);
1440 }
1441
1442 *Memory = Start;
1443 }
1444
1445 return Status;
1446 }
1447
1448 /**
1449 Allocates pages from the memory map.
1450
1451 @param Type The type of allocation to perform
1452 @param MemoryType The type of memory to turn the allocated pages
1453 into
1454 @param NumberOfPages The number of pages to allocate
1455 @param Memory A pointer to receive the base allocated memory
1456 address
1457
1458 @return Status. On success, Memory is filled in with the base address allocated
1459 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1460 spec.
1461 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1462 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1463 @retval EFI_SUCCESS Pages successfully allocated.
1464
1465 **/
1466 EFI_STATUS
1467 EFIAPI
1468 CoreAllocatePages (
1469 IN EFI_ALLOCATE_TYPE Type,
1470 IN EFI_MEMORY_TYPE MemoryType,
1471 IN UINTN NumberOfPages,
1472 OUT EFI_PHYSICAL_ADDRESS *Memory
1473 )
1474 {
1475 EFI_STATUS Status;
1476 BOOLEAN NeedGuard;
1477
1478 NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
1479 Status = CoreInternalAllocatePages (
1480 Type,
1481 MemoryType,
1482 NumberOfPages,
1483 Memory,
1484 NeedGuard
1485 );
1486 if (!EFI_ERROR (Status)) {
1487 CoreUpdateProfile (
1488 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
1489 MemoryProfileActionAllocatePages,
1490 MemoryType,
1491 EFI_PAGES_TO_SIZE (NumberOfPages),
1492 (VOID *)(UINTN)*Memory,
1493 NULL
1494 );
1495 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1496 ApplyMemoryProtectionPolicy (
1497 EfiConventionalMemory,
1498 MemoryType,
1499 *Memory,
1500 EFI_PAGES_TO_SIZE (NumberOfPages)
1501 );
1502 }
1503
1504 return Status;
1505 }
1506
1507 /**
1508 Frees previous allocated pages.
1509
1510 @param Memory Base address of memory being freed
1511 @param NumberOfPages The number of pages to free
1512 @param MemoryType Pointer to memory type
1513
1514 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1515 @retval EFI_INVALID_PARAMETER Address not aligned
1516 @return EFI_SUCCESS -Pages successfully freed.
1517
1518 **/
1519 EFI_STATUS
1520 EFIAPI
1521 CoreInternalFreePages (
1522 IN EFI_PHYSICAL_ADDRESS Memory,
1523 IN UINTN NumberOfPages,
1524 OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
1525 )
1526 {
1527 EFI_STATUS Status;
1528 LIST_ENTRY *Link;
1529 MEMORY_MAP *Entry;
1530 UINTN Alignment;
1531 BOOLEAN IsGuarded;
1532
1533 //
1534 // Free the range
1535 //
1536 CoreAcquireMemoryLock ();
1537
1538 //
1539 // Find the entry that the covers the range
1540 //
1541 IsGuarded = FALSE;
1542 Entry = NULL;
1543 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1544 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1545 if ((Entry->Start <= Memory) && (Entry->End > Memory)) {
1546 break;
1547 }
1548 }
1549
1550 if (Link == &gMemoryMap) {
1551 Status = EFI_NOT_FOUND;
1552 goto Done;
1553 }
1554
1555 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1556
1557 ASSERT (Entry != NULL);
1558 if ((Entry->Type == EfiACPIReclaimMemory) ||
1559 (Entry->Type == EfiACPIMemoryNVS) ||
1560 (Entry->Type == EfiRuntimeServicesCode) ||
1561 (Entry->Type == EfiRuntimeServicesData))
1562 {
1563 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1564 }
1565
1566 if ((Memory & (Alignment - 1)) != 0) {
1567 Status = EFI_INVALID_PARAMETER;
1568 goto Done;
1569 }
1570
1571 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1572 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1573
1574 if (MemoryType != NULL) {
1575 *MemoryType = Entry->Type;
1576 }
1577
1578 IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
1579 IsMemoryGuarded (Memory);
1580 if (IsGuarded) {
1581 Status = CoreConvertPagesWithGuard (
1582 Memory,
1583 NumberOfPages,
1584 EfiConventionalMemory
1585 );
1586 } else {
1587 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1588 }
1589
1590 Done:
1591 CoreReleaseMemoryLock ();
1592 return Status;
1593 }
1594
1595 /**
1596 Frees previous allocated pages.
1597
1598 @param Memory Base address of memory being freed
1599 @param NumberOfPages The number of pages to free
1600
1601 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1602 @retval EFI_INVALID_PARAMETER Address not aligned
1603 @return EFI_SUCCESS -Pages successfully freed.
1604
1605 **/
1606 EFI_STATUS
1607 EFIAPI
1608 CoreFreePages (
1609 IN EFI_PHYSICAL_ADDRESS Memory,
1610 IN UINTN NumberOfPages
1611 )
1612 {
1613 EFI_STATUS Status;
1614 EFI_MEMORY_TYPE MemoryType;
1615
1616 Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
1617 if (!EFI_ERROR (Status)) {
1618 GuardFreedPagesChecked (Memory, NumberOfPages);
1619 CoreUpdateProfile (
1620 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
1621 MemoryProfileActionFreePages,
1622 MemoryType,
1623 EFI_PAGES_TO_SIZE (NumberOfPages),
1624 (VOID *)(UINTN)Memory,
1625 NULL
1626 );
1627 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1628 ApplyMemoryProtectionPolicy (
1629 MemoryType,
1630 EfiConventionalMemory,
1631 Memory,
1632 EFI_PAGES_TO_SIZE (NumberOfPages)
1633 );
1634 }
1635
1636 return Status;
1637 }
1638
1639 /**
1640 This function checks to see if the last memory map descriptor in a memory map
1641 can be merged with any of the other memory map descriptors in a memorymap.
1642 Memory descriptors may be merged if they are adjacent and have the same type
1643 and attributes.
1644
1645 @param MemoryMap A pointer to the start of the memory map.
1646 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1647 @param DescriptorSize The size, in bytes, of an individual
1648 EFI_MEMORY_DESCRIPTOR.
1649
1650 @return A pointer to the next available descriptor in MemoryMap
1651
1652 **/
1653 EFI_MEMORY_DESCRIPTOR *
1654 MergeMemoryMapDescriptor (
1655 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
1656 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
1657 IN UINTN DescriptorSize
1658 )
1659 {
1660 //
1661 // Traverse the array of descriptors in MemoryMap
1662 //
1663 for ( ; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1664 //
1665 // Check to see if the Type fields are identical.
1666 //
1667 if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1668 continue;
1669 }
1670
1671 //
1672 // Check to see if the Attribute fields are identical.
1673 //
1674 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1675 continue;
1676 }
1677
1678 //
1679 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1680 //
1681 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1682 //
1683 // Merge MemoryMapDescriptor into MemoryMap
1684 //
1685 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1686
1687 //
1688 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1689 //
1690 return MemoryMapDescriptor;
1691 }
1692
1693 //
1694 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1695 //
1696 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1697 //
1698 // Merge MemoryMapDescriptor into MemoryMap
1699 //
1700 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
1701 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
1702 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1703
1704 //
1705 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1706 //
1707 return MemoryMapDescriptor;
1708 }
1709 }
1710
1711 //
1712 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1713 //
1714 // Return the slot immediately after MemoryMapDescriptor as the next available
1715 // slot in the MemoryMap array
1716 //
1717 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1718 }
1719
1720 /**
1721 This function returns a copy of the current memory map. The map is an array of
1722 memory descriptors, each of which describes a contiguous block of memory.
1723
1724 @param MemoryMapSize A pointer to the size, in bytes, of the
1725 MemoryMap buffer. On input, this is the size of
1726 the buffer allocated by the caller. On output,
1727 it is the size of the buffer returned by the
1728 firmware if the buffer was large enough, or the
1729 size of the buffer needed to contain the map if
1730 the buffer was too small.
1731 @param MemoryMap A pointer to the buffer in which firmware places
1732 the current memory map.
1733 @param MapKey A pointer to the location in which firmware
1734 returns the key for the current memory map.
1735 @param DescriptorSize A pointer to the location in which firmware
1736 returns the size, in bytes, of an individual
1737 EFI_MEMORY_DESCRIPTOR.
1738 @param DescriptorVersion A pointer to the location in which firmware
1739 returns the version number associated with the
1740 EFI_MEMORY_DESCRIPTOR.
1741
1742 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1743 buffer.
1744 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1745 buffer size needed to hold the memory map is
1746 returned in MemoryMapSize.
1747 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1748
1749 **/
1750 EFI_STATUS
1751 EFIAPI
1752 CoreGetMemoryMap (
1753 IN OUT UINTN *MemoryMapSize,
1754 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1755 OUT UINTN *MapKey,
1756 OUT UINTN *DescriptorSize,
1757 OUT UINT32 *DescriptorVersion
1758 )
1759 {
1760 EFI_STATUS Status;
1761 UINTN Size;
1762 UINTN BufferSize;
1763 UINTN NumberOfEntries;
1764 LIST_ENTRY *Link;
1765 MEMORY_MAP *Entry;
1766 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1767 EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
1768 EFI_MEMORY_TYPE Type;
1769 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1770 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
1771
1772 //
1773 // Make sure the parameters are valid
1774 //
1775 if (MemoryMapSize == NULL) {
1776 return EFI_INVALID_PARAMETER;
1777 }
1778
1779 CoreAcquireGcdMemoryLock ();
1780
1781 //
1782 // Count the number of Reserved and runtime MMIO entries
1783 // And, count the number of Persistent entries.
1784 //
1785 NumberOfEntries = 0;
1786 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1787 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1788 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
1789 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1790 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1791 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
1792 {
1793 NumberOfEntries++;
1794 }
1795 }
1796
1797 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1798
1799 //
1800 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1801 // prevent people from having pointer math bugs in their code.
1802 // now you have to use *DescriptorSize to make things work.
1803 //
1804 Size += sizeof (UINT64) - (Size % sizeof (UINT64));
1805
1806 if (DescriptorSize != NULL) {
1807 *DescriptorSize = Size;
1808 }
1809
1810 if (DescriptorVersion != NULL) {
1811 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1812 }
1813
1814 CoreAcquireMemoryLock ();
1815
1816 //
1817 // Compute the buffer size needed to fit the entire map
1818 //
1819 BufferSize = Size * NumberOfEntries;
1820 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1821 BufferSize += Size;
1822 }
1823
1824 if (*MemoryMapSize < BufferSize) {
1825 Status = EFI_BUFFER_TOO_SMALL;
1826 goto Done;
1827 }
1828
1829 if (MemoryMap == NULL) {
1830 Status = EFI_INVALID_PARAMETER;
1831 goto Done;
1832 }
1833
1834 //
1835 // Build the map
1836 //
1837 ZeroMem (MemoryMap, BufferSize);
1838 MemoryMapStart = MemoryMap;
1839 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1840 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1841 ASSERT (Entry->VirtualStart == 0);
1842
1843 //
1844 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1845 //
1846 MemoryMap->Type = Entry->Type;
1847 MemoryMap->PhysicalStart = Entry->Start;
1848 MemoryMap->VirtualStart = Entry->VirtualStart;
1849 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1850 //
1851 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1852 // memory type bin and needs to be converted to the same memory type as the rest of the
1853 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1854 // improves the chances for a successful S4 resume in the presence of minor page allocation
1855 // differences across reboots.
1856 //
1857 if (MemoryMap->Type == EfiConventionalMemory) {
1858 for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {
1859 if (mMemoryTypeStatistics[Type].Special &&
1860 (mMemoryTypeStatistics[Type].NumberOfPages > 0) &&
1861 (Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress) &&
1862 (Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress))
1863 {
1864 MemoryMap->Type = Type;
1865 }
1866 }
1867 }
1868
1869 MemoryMap->Attribute = Entry->Attribute;
1870 if (MemoryMap->Type < EfiMaxMemoryType) {
1871 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1872 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1873 }
1874 }
1875
1876 //
1877 // Check to see if the new Memory Map Descriptor can be merged with an
1878 // existing descriptor if they are adjacent and have the same attributes
1879 //
1880 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1881 }
1882
1883 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1884 GcdMapEntry = NULL;
1885 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1886 if (Link != &mGcdMemorySpaceMap) {
1887 //
1888 // Merge adjacent same type and attribute GCD memory range
1889 //
1890 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1891
1892 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1893 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1894 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1895 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType))
1896 {
1897 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
1898 continue;
1899 }
1900 }
1901
1902 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1903 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1904 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))
1905 {
1906 //
1907 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1908 // it will be recorded as page PhysicalStart and NumberOfPages.
1909 //
1910 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1911 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1912
1913 //
1914 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1915 //
1916 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1917 MemoryMap->VirtualStart = 0;
1918 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1919 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1920 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
1921
1922 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1923 MemoryMap->Type = EfiReservedMemoryType;
1924 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1925 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1926 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1927 } else {
1928 MemoryMap->Type = EfiMemoryMappedIO;
1929 }
1930 }
1931
1932 //
1933 // Check to see if the new Memory Map Descriptor can be merged with an
1934 // existing descriptor if they are adjacent and have the same attributes
1935 //
1936 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1937 }
1938
1939 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
1940 //
1941 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1942 // it will be recorded as page PhysicalStart and NumberOfPages.
1943 //
1944 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1945 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1946
1947 //
1948 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1949 //
1950 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1951 MemoryMap->VirtualStart = 0;
1952 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1953 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1954 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
1955 MemoryMap->Type = EfiPersistentMemory;
1956
1957 //
1958 // Check to see if the new Memory Map Descriptor can be merged with an
1959 // existing descriptor if they are adjacent and have the same attributes
1960 //
1961 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1962 }
1963
1964 if (Link == &mGcdMemorySpaceMap) {
1965 //
1966 // break loop when arrive at head.
1967 //
1968 break;
1969 }
1970
1971 if (GcdMapEntry != NULL) {
1972 //
1973 // Copy new GCD map entry for the following GCD range merge
1974 //
1975 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1976 }
1977 }
1978
1979 //
1980 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1981 //
1982 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1983
1984 //
1985 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1986 // set attributes and change memory paging attribute accordingly.
1987 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1988 // value from Capabilities in GCD memory map. This might cause
1989 // boot problems. Clearing all page-access permission related
1990 // capabilities can workaround it. Following code is supposed to
1991 // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute
1992 // is clarified in UEFI spec and adopted by both EDK-II Core and
1993 // all supported OSs.
1994 //
1995 MemoryMapEnd = MemoryMap;
1996 MemoryMap = MemoryMapStart;
1997 while (MemoryMap < MemoryMapEnd) {
1998 MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;
1999 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
2000 }
2001
2002 MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
2003 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
2004
2005 Status = EFI_SUCCESS;
2006
2007 Done:
2008 //
2009 // Update the map key finally
2010 //
2011 if (MapKey != NULL) {
2012 *MapKey = mMemoryMapKey;
2013 }
2014
2015 CoreReleaseMemoryLock ();
2016
2017 CoreReleaseGcdMemoryLock ();
2018
2019 *MemoryMapSize = BufferSize;
2020
2021 DEBUG_CODE (
2022 DumpGuardedMemoryBitmap ();
2023 );
2024
2025 return Status;
2026 }
2027
2028 /**
2029 Internal function. Used by the pool functions to allocate pages
2030 to back pool allocation requests.
2031
2032 @param PoolType The type of memory for the new pool pages
2033 @param NumberOfPages No of pages to allocate
2034 @param Alignment Bits to align.
2035 @param NeedGuard Flag to indicate Guard page is needed or not
2036
2037 @return The allocated memory, or NULL
2038
2039 **/
2040 VOID *
2041 CoreAllocatePoolPages (
2042 IN EFI_MEMORY_TYPE PoolType,
2043 IN UINTN NumberOfPages,
2044 IN UINTN Alignment,
2045 IN BOOLEAN NeedGuard
2046 )
2047 {
2048 UINT64 Start;
2049
2050 //
2051 // Find the pages to convert
2052 //
2053 Start = FindFreePages (
2054 MAX_ALLOC_ADDRESS,
2055 NumberOfPages,
2056 PoolType,
2057 Alignment,
2058 NeedGuard
2059 );
2060
2061 //
2062 // Convert it to boot services data
2063 //
2064 if (Start == 0) {
2065 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
2066 } else {
2067 if (NeedGuard) {
2068 CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
2069 } else {
2070 CoreConvertPages (Start, NumberOfPages, PoolType);
2071 }
2072 }
2073
2074 return (VOID *)(UINTN)Start;
2075 }
2076
2077 /**
2078 Internal function. Frees pool pages allocated via AllocatePoolPages ()
2079
2080 @param Memory The base address to free
2081 @param NumberOfPages The number of pages to free
2082
2083 **/
2084 VOID
2085 CoreFreePoolPages (
2086 IN EFI_PHYSICAL_ADDRESS Memory,
2087 IN UINTN NumberOfPages
2088 )
2089 {
2090 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
2091 }
2092
2093 /**
2094 Make sure the memory map is following all the construction rules,
2095 it is the last time to check memory map error before exit boot services.
2096
2097 @param MapKey Memory map key
2098
2099 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2100 rules.
2101 @retval EFI_SUCCESS Valid memory map.
2102
2103 **/
2104 EFI_STATUS
2105 CoreTerminateMemoryMap (
2106 IN UINTN MapKey
2107 )
2108 {
2109 EFI_STATUS Status;
2110 LIST_ENTRY *Link;
2111 MEMORY_MAP *Entry;
2112
2113 Status = EFI_SUCCESS;
2114
2115 CoreAcquireMemoryLock ();
2116
2117 if (MapKey == mMemoryMapKey) {
2118 //
2119 // Make sure the memory map is following all the construction rules
2120 // This is the last chance we will be able to display any messages on
2121 // the console devices.
2122 //
2123
2124 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
2125 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
2126 if (Entry->Type < EfiMaxMemoryType) {
2127 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
2128 ASSERT (Entry->Type != EfiACPIReclaimMemory);
2129 ASSERT (Entry->Type != EfiACPIMemoryNVS);
2130 if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2131 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2132 Status = EFI_INVALID_PARAMETER;
2133 goto Done;
2134 }
2135
2136 if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2137 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2138 Status = EFI_INVALID_PARAMETER;
2139 goto Done;
2140 }
2141 }
2142 }
2143 }
2144
2145 //
2146 // The map key they gave us matches what we expect. Fall through and
2147 // return success. In an ideal world we would clear out all of
2148 // EfiBootServicesCode and EfiBootServicesData. However this function
2149 // is not the last one called by ExitBootServices(), so we have to
2150 // preserve the memory contents.
2151 //
2152 } else {
2153 Status = EFI_INVALID_PARAMETER;
2154 }
2155
2156 Done:
2157 CoreReleaseMemoryLock ();
2158
2159 return Status;
2160 }