]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg DxeCore: Address boundary check for Type AllocateAddress
[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 funciton
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 ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory);
1339 }
1340 return Status;
1341 }
1342
1343 /**
1344 Frees previous allocated pages.
1345
1346 @param Memory Base address of memory being freed
1347 @param NumberOfPages The number of pages to free
1348
1349 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1350 @retval EFI_INVALID_PARAMETER Address not aligned
1351 @return EFI_SUCCESS -Pages successfully freed.
1352
1353 **/
1354 EFI_STATUS
1355 EFIAPI
1356 CoreInternalFreePages (
1357 IN EFI_PHYSICAL_ADDRESS Memory,
1358 IN UINTN NumberOfPages
1359 )
1360 {
1361 EFI_STATUS Status;
1362 LIST_ENTRY *Link;
1363 MEMORY_MAP *Entry;
1364 UINTN Alignment;
1365
1366 //
1367 // Free the range
1368 //
1369 CoreAcquireMemoryLock ();
1370
1371 //
1372 // Find the entry that the covers the range
1373 //
1374 Entry = NULL;
1375 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1376 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1377 if (Entry->Start <= Memory && Entry->End > Memory) {
1378 break;
1379 }
1380 }
1381 if (Link == &gMemoryMap) {
1382 Status = EFI_NOT_FOUND;
1383 goto Done;
1384 }
1385
1386 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1387
1388 ASSERT (Entry != NULL);
1389 if (Entry->Type == EfiACPIReclaimMemory ||
1390 Entry->Type == EfiACPIMemoryNVS ||
1391 Entry->Type == EfiRuntimeServicesCode ||
1392 Entry->Type == EfiRuntimeServicesData) {
1393
1394 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1395
1396 }
1397
1398 if ((Memory & (Alignment - 1)) != 0) {
1399 Status = EFI_INVALID_PARAMETER;
1400 goto Done;
1401 }
1402
1403 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1404 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1405
1406 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1407
1408 if (EFI_ERROR (Status)) {
1409 goto Done;
1410 }
1411
1412 Done:
1413 CoreReleaseMemoryLock ();
1414 return Status;
1415 }
1416
1417 /**
1418 Frees previous allocated pages.
1419
1420 @param Memory Base address of memory being freed
1421 @param NumberOfPages The number of pages to free
1422
1423 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1424 @retval EFI_INVALID_PARAMETER Address not aligned
1425 @return EFI_SUCCESS -Pages successfully freed.
1426
1427 **/
1428 EFI_STATUS
1429 EFIAPI
1430 CoreFreePages (
1431 IN EFI_PHYSICAL_ADDRESS Memory,
1432 IN UINTN NumberOfPages
1433 )
1434 {
1435 EFI_STATUS Status;
1436
1437 Status = CoreInternalFreePages (Memory, NumberOfPages);
1438 if (!EFI_ERROR (Status)) {
1439 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, (EFI_MEMORY_TYPE) 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory);
1440 }
1441 return Status;
1442 }
1443
1444 /**
1445 This function checks to see if the last memory map descriptor in a memory map
1446 can be merged with any of the other memory map descriptors in a memorymap.
1447 Memory descriptors may be merged if they are adjacent and have the same type
1448 and attributes.
1449
1450 @param MemoryMap A pointer to the start of the memory map.
1451 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1452 @param DescriptorSize The size, in bytes, of an individual
1453 EFI_MEMORY_DESCRIPTOR.
1454
1455 @return A pointer to the next available descriptor in MemoryMap
1456
1457 **/
1458 EFI_MEMORY_DESCRIPTOR *
1459 MergeMemoryMapDescriptor (
1460 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
1461 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
1462 IN UINTN DescriptorSize
1463 )
1464 {
1465 //
1466 // Traverse the array of descriptors in MemoryMap
1467 //
1468 for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1469 //
1470 // Check to see if the Type fields are identical.
1471 //
1472 if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1473 continue;
1474 }
1475
1476 //
1477 // Check to see if the Attribute fields are identical.
1478 //
1479 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1480 continue;
1481 }
1482
1483 //
1484 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1485 //
1486 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1487 //
1488 // Merge MemoryMapDescriptor into MemoryMap
1489 //
1490 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1491
1492 //
1493 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1494 //
1495 return MemoryMapDescriptor;
1496 }
1497
1498 //
1499 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1500 //
1501 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1502 //
1503 // Merge MemoryMapDescriptor into MemoryMap
1504 //
1505 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
1506 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
1507 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1508
1509 //
1510 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1511 //
1512 return MemoryMapDescriptor;
1513 }
1514 }
1515
1516 //
1517 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1518 //
1519 // Return the slot immediately after MemoryMapDescriptor as the next available
1520 // slot in the MemoryMap array
1521 //
1522 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1523 }
1524
1525 /**
1526 This function returns a copy of the current memory map. The map is an array of
1527 memory descriptors, each of which describes a contiguous block of memory.
1528
1529 @param MemoryMapSize A pointer to the size, in bytes, of the
1530 MemoryMap buffer. On input, this is the size of
1531 the buffer allocated by the caller. On output,
1532 it is the size of the buffer returned by the
1533 firmware if the buffer was large enough, or the
1534 size of the buffer needed to contain the map if
1535 the buffer was too small.
1536 @param MemoryMap A pointer to the buffer in which firmware places
1537 the current memory map.
1538 @param MapKey A pointer to the location in which firmware
1539 returns the key for the current memory map.
1540 @param DescriptorSize A pointer to the location in which firmware
1541 returns the size, in bytes, of an individual
1542 EFI_MEMORY_DESCRIPTOR.
1543 @param DescriptorVersion A pointer to the location in which firmware
1544 returns the version number associated with the
1545 EFI_MEMORY_DESCRIPTOR.
1546
1547 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1548 buffer.
1549 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1550 buffer size needed to hold the memory map is
1551 returned in MemoryMapSize.
1552 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1553
1554 **/
1555 EFI_STATUS
1556 EFIAPI
1557 CoreGetMemoryMap (
1558 IN OUT UINTN *MemoryMapSize,
1559 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1560 OUT UINTN *MapKey,
1561 OUT UINTN *DescriptorSize,
1562 OUT UINT32 *DescriptorVersion
1563 )
1564 {
1565 EFI_STATUS Status;
1566 UINTN Size;
1567 UINTN BufferSize;
1568 UINTN NumberOfEntries;
1569 LIST_ENTRY *Link;
1570 MEMORY_MAP *Entry;
1571 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1572 EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
1573 EFI_MEMORY_TYPE Type;
1574 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1575
1576 //
1577 // Make sure the parameters are valid
1578 //
1579 if (MemoryMapSize == NULL) {
1580 return EFI_INVALID_PARAMETER;
1581 }
1582
1583 CoreAcquireGcdMemoryLock ();
1584
1585 //
1586 // Count the number of Reserved and runtime MMIO entries
1587 // And, count the number of Persistent entries.
1588 //
1589 NumberOfEntries = 0;
1590 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1591 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1592 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) ||
1593 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1594 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1595 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1596 NumberOfEntries ++;
1597 }
1598 }
1599
1600 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1601
1602 //
1603 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1604 // prevent people from having pointer math bugs in their code.
1605 // now you have to use *DescriptorSize to make things work.
1606 //
1607 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1608
1609 if (DescriptorSize != NULL) {
1610 *DescriptorSize = Size;
1611 }
1612
1613 if (DescriptorVersion != NULL) {
1614 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1615 }
1616
1617 CoreAcquireMemoryLock ();
1618
1619 //
1620 // Compute the buffer size needed to fit the entire map
1621 //
1622 BufferSize = Size * NumberOfEntries;
1623 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1624 BufferSize += Size;
1625 }
1626
1627 if (*MemoryMapSize < BufferSize) {
1628 Status = EFI_BUFFER_TOO_SMALL;
1629 goto Done;
1630 }
1631
1632 if (MemoryMap == NULL) {
1633 Status = EFI_INVALID_PARAMETER;
1634 goto Done;
1635 }
1636
1637 //
1638 // Build the map
1639 //
1640 ZeroMem (MemoryMap, BufferSize);
1641 MemoryMapStart = MemoryMap;
1642 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1643 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1644 ASSERT (Entry->VirtualStart == 0);
1645
1646 //
1647 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1648 //
1649 MemoryMap->Type = Entry->Type;
1650 MemoryMap->PhysicalStart = Entry->Start;
1651 MemoryMap->VirtualStart = Entry->VirtualStart;
1652 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1653 //
1654 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1655 // memory type bin and needs to be converted to the same memory type as the rest of the
1656 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1657 // improves the chances for a successful S4 resume in the presence of minor page allocation
1658 // differences across reboots.
1659 //
1660 if (MemoryMap->Type == EfiConventionalMemory) {
1661 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1662 if (mMemoryTypeStatistics[Type].Special &&
1663 mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
1664 Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
1665 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
1666 MemoryMap->Type = Type;
1667 }
1668 }
1669 }
1670 MemoryMap->Attribute = Entry->Attribute;
1671 if (MemoryMap->Type < EfiMaxMemoryType) {
1672 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1673 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1674 }
1675 }
1676
1677 //
1678 // Check to see if the new Memory Map Descriptor can be merged with an
1679 // existing descriptor if they are adjacent and have the same attributes
1680 //
1681 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1682 }
1683
1684
1685 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1686 GcdMapEntry = NULL;
1687 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1688 if (Link != &mGcdMemorySpaceMap) {
1689 //
1690 // Merge adjacent same type and attribute GCD memory range
1691 //
1692 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1693
1694 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1695 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1696 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1697 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
1698 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
1699 continue;
1700 }
1701 }
1702
1703 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1704 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1705 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1706 //
1707 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1708 // it will be recorded as page PhysicalStart and NumberOfPages.
1709 //
1710 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1711 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1712
1713 //
1714 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1715 //
1716 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1717 MemoryMap->VirtualStart = 0;
1718 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1719 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1720 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1721 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1722
1723 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1724 MemoryMap->Type = EfiReservedMemoryType;
1725 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1726 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1727 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1728 } else {
1729 MemoryMap->Type = EfiMemoryMappedIO;
1730 }
1731 }
1732
1733 //
1734 // Check to see if the new Memory Map Descriptor can be merged with an
1735 // existing descriptor if they are adjacent and have the same attributes
1736 //
1737 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1738 }
1739
1740 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {
1741 //
1742 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1743 // it will be recorded as page PhysicalStart and NumberOfPages.
1744 //
1745 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1746 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1747
1748 //
1749 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1750 //
1751 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1752 MemoryMap->VirtualStart = 0;
1753 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1754 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1755 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1756 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1757 MemoryMap->Type = EfiPersistentMemory;
1758
1759 //
1760 // Check to see if the new Memory Map Descriptor can be merged with an
1761 // existing descriptor if they are adjacent and have the same attributes
1762 //
1763 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1764 }
1765 if (Link == &mGcdMemorySpaceMap) {
1766 //
1767 // break loop when arrive at head.
1768 //
1769 break;
1770 }
1771 if (GcdMapEntry != NULL) {
1772 //
1773 // Copy new GCD map entry for the following GCD range merge
1774 //
1775 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1776 }
1777 }
1778
1779 //
1780 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1781 //
1782 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1783
1784 Status = EFI_SUCCESS;
1785
1786 Done:
1787 //
1788 // Update the map key finally
1789 //
1790 if (MapKey != NULL) {
1791 *MapKey = mMemoryMapKey;
1792 }
1793
1794 CoreReleaseMemoryLock ();
1795
1796 CoreReleaseGcdMemoryLock ();
1797
1798 *MemoryMapSize = BufferSize;
1799
1800 return Status;
1801 }
1802
1803
1804 /**
1805 Internal function. Used by the pool functions to allocate pages
1806 to back pool allocation requests.
1807
1808 @param PoolType The type of memory for the new pool pages
1809 @param NumberOfPages No of pages to allocate
1810 @param Alignment Bits to align.
1811
1812 @return The allocated memory, or NULL
1813
1814 **/
1815 VOID *
1816 CoreAllocatePoolPages (
1817 IN EFI_MEMORY_TYPE PoolType,
1818 IN UINTN NumberOfPages,
1819 IN UINTN Alignment
1820 )
1821 {
1822 UINT64 Start;
1823
1824 //
1825 // Find the pages to convert
1826 //
1827 Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
1828
1829 //
1830 // Convert it to boot services data
1831 //
1832 if (Start == 0) {
1833 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1834 } else {
1835 CoreConvertPages (Start, NumberOfPages, PoolType);
1836 }
1837
1838 return (VOID *)(UINTN) Start;
1839 }
1840
1841
1842 /**
1843 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1844
1845 @param Memory The base address to free
1846 @param NumberOfPages The number of pages to free
1847
1848 **/
1849 VOID
1850 CoreFreePoolPages (
1851 IN EFI_PHYSICAL_ADDRESS Memory,
1852 IN UINTN NumberOfPages
1853 )
1854 {
1855 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1856 }
1857
1858
1859
1860 /**
1861 Make sure the memory map is following all the construction rules,
1862 it is the last time to check memory map error before exit boot services.
1863
1864 @param MapKey Memory map key
1865
1866 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1867 rules.
1868 @retval EFI_SUCCESS Valid memory map.
1869
1870 **/
1871 EFI_STATUS
1872 CoreTerminateMemoryMap (
1873 IN UINTN MapKey
1874 )
1875 {
1876 EFI_STATUS Status;
1877 LIST_ENTRY *Link;
1878 MEMORY_MAP *Entry;
1879
1880 Status = EFI_SUCCESS;
1881
1882 CoreAcquireMemoryLock ();
1883
1884 if (MapKey == mMemoryMapKey) {
1885
1886 //
1887 // Make sure the memory map is following all the construction rules
1888 // This is the last chance we will be able to display any messages on
1889 // the console devices.
1890 //
1891
1892 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1893 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1894 if (Entry->Type < EfiMaxMemoryType) {
1895 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
1896 ASSERT (Entry->Type != EfiACPIReclaimMemory);
1897 ASSERT (Entry->Type != EfiACPIMemoryNVS);
1898 if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1899 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1900 Status = EFI_INVALID_PARAMETER;
1901 goto Done;
1902 }
1903 if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1904 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1905 Status = EFI_INVALID_PARAMETER;
1906 goto Done;
1907 }
1908 }
1909 }
1910 }
1911
1912 //
1913 // The map key they gave us matches what we expect. Fall through and
1914 // return success. In an ideal world we would clear out all of
1915 // EfiBootServicesCode and EfiBootServicesData. However this function
1916 // is not the last one called by ExitBootServices(), so we have to
1917 // preserve the memory contents.
1918 //
1919 } else {
1920 Status = EFI_INVALID_PARAMETER;
1921 }
1922
1923 Done:
1924 CoreReleaseMemoryLock ();
1925
1926 return Status;
1927 }
1928
1929
1930
1931
1932
1933
1934
1935
1936