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