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