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