]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/Dxe/Mem/Page.c
d14468945f2615762f90becbeb27e777807a7cfa
[mirror_edk2.git] / EdkModulePkg / Core / Dxe / Mem / Page.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 page.c
15
16 Abstract:
17
18 EFI Memory page management
19
20
21 Revision History
22
23 --*/
24
25 #include <DxeMain.h>
26
27 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
28
29 //
30 // Entry for tracking the memory regions for each memory type to help cooalese like memory types
31 //
32 typedef struct {
33 EFI_PHYSICAL_ADDRESS BaseAddress;
34 EFI_PHYSICAL_ADDRESS MaximumAddress;
35 UINT64 CurrentNumberOfPages;
36 UINTN InformationIndex;
37 } EFI_MEMORY_TYPE_STAISTICS;
38
39 //
40 // MemoryMap - The current memory map
41 //
42 UINTN mMemoryMapKey = 0;
43
44 //
45 // mMapStack - space to use as temp storage to build new map descriptors
46 // mMapDepth - depth of new descriptor stack
47 //
48
49 #define MAX_MAP_DEPTH 6
50 UINTN mMapDepth = 0;
51 MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
52 UINTN mFreeMapStack = 0;
53
54 BOOLEAN mMemoryTypeInformationInitialized = FALSE;
55
56 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
57 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiReservedMemoryType
58 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderCode
59 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderData
60 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesCode
61 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesData
62 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesCode
63 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesData
64 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiConventionalMemory
65 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiUnusableMemory
66 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIReclaimMemory
67 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIMemoryNVS
68 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIO
69 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIOPortSpace
70 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiPalCode
71 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType } // EfiMaxMemoryType
72 };
73
74 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;
75
76 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
77 { EfiReservedMemoryType, 0 },
78 { EfiLoaderCode, 0 },
79 { EfiLoaderData, 0 },
80 { EfiBootServicesCode, 0 },
81 { EfiBootServicesData, 0 },
82 { EfiRuntimeServicesCode, 0 },
83 { EfiRuntimeServicesData, 0 },
84 { EfiConventionalMemory, 0 },
85 { EfiUnusableMemory, 0 },
86 { EfiACPIReclaimMemory, 0 },
87 { EfiACPIMemoryNVS, 0 },
88 { EfiMemoryMappedIO, 0 },
89 { EfiMemoryMappedIOPortSpace, 0 },
90 { EfiPalCode, 0 },
91 { EfiMaxMemoryType, 0 }
92 };
93
94 //
95 // Internal prototypes
96 //
97 VOID
98 PromoteMemoryResource (
99 VOID
100 );
101
102 STATIC
103 VOID
104 CoreAddRange (
105 IN EFI_MEMORY_TYPE Type,
106 IN EFI_PHYSICAL_ADDRESS Start,
107 IN EFI_PHYSICAL_ADDRESS End,
108 IN UINT64 Attribute
109 );
110
111 STATIC
112 VOID
113 CoreFreeMemoryMapStack (
114 VOID
115 );
116
117 STATIC
118 EFI_STATUS
119 CoreConvertPages (
120 IN UINT64 Start,
121 IN UINT64 NumberOfPages,
122 IN EFI_MEMORY_TYPE NewType
123 );
124
125 STATIC
126 VOID
127 RemoveMemoryMapEntry (
128 MEMORY_MAP *Entry
129 );
130
131 VOID
132 CoreAcquireMemoryLock (
133 VOID
134 )
135 /*++
136
137 Routine Description:
138
139 Enter critical section by gaining lock on gMemoryLock
140
141 Arguments:
142
143 None
144
145 Returns:
146
147 None
148
149 --*/
150 {
151 CoreAcquireLock (&gMemoryLock);
152 }
153
154
155 VOID
156 CoreReleaseMemoryLock (
157 VOID
158 )
159 /*++
160
161 Routine Description:
162
163 Exit critical section by releasing lock on gMemoryLock
164
165 Arguments:
166
167 None
168
169 Returns:
170
171 None
172
173 --*/
174 {
175 CoreReleaseLock (&gMemoryLock);
176 }
177
178 VOID
179 PromoteMemoryResource (
180 VOID
181 )
182 /*++
183
184 Routine Description:
185
186 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
187
188 Arguments:
189
190 None
191
192 Returns:
193
194 None
195
196 --*/
197 {
198 LIST_ENTRY *Link;
199 EFI_GCD_MAP_ENTRY *Entry;
200
201 DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "Promote the memory resource\n"));
202
203 CoreAcquireGcdMemoryLock ();
204
205 Link = mGcdMemorySpaceMap.ForwardLink;
206 while (Link != &mGcdMemorySpaceMap) {
207
208 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
209
210 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
211 Entry->EndAddress < EFI_MAX_ADDRESS &&
212 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
213 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
214 //
215 // Update the GCD map
216 //
217 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
218 Entry->Capabilities |= EFI_MEMORY_TESTED;
219 Entry->ImageHandle = gDxeCoreImageHandle;
220 Entry->DeviceHandle = NULL;
221
222 //
223 // Add to allocable system memory resource
224 //
225
226 CoreAddRange (
227 EfiConventionalMemory,
228 Entry->BaseAddress,
229 Entry->EndAddress,
230 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
231 );
232 CoreFreeMemoryMapStack ();
233
234 }
235
236 Link = Link->ForwardLink;
237 }
238
239 CoreReleaseGcdMemoryLock ();
240
241 return;
242 }
243
244 VOID
245 CoreAddMemoryDescriptor (
246 IN EFI_MEMORY_TYPE Type,
247 IN EFI_PHYSICAL_ADDRESS Start,
248 IN UINT64 NumberOfPages,
249 IN UINT64 Attribute
250 )
251 /*++
252
253 Routine Description:
254
255 Called to initialize the memory map and add descriptors to
256 the current descriptor list.
257
258 The first descriptor that is added must be general usable
259 memory as the addition allocates heap.
260
261 Arguments:
262
263 Type - The type of memory to add
264
265 Start - The starting address in the memory range
266 Must be page aligned
267
268 NumberOfPages - The number of pages in the range
269
270 Attribute - Attributes of the memory to add
271
272 Returns:
273
274 None. The range is added to the memory map
275
276 --*/
277 {
278 EFI_PHYSICAL_ADDRESS End;
279 EFI_STATUS Status;
280 UINTN Index;
281 UINTN FreeIndex;
282
283 if ((Start & EFI_PAGE_MASK) != 0) {
284 return;
285 }
286
287 if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {
288 return;
289 }
290
291 CoreAcquireMemoryLock ();
292 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
293 CoreAddRange (Type, Start, End, Attribute);
294 CoreFreeMemoryMapStack ();
295 CoreReleaseMemoryLock ();
296
297 //
298 // Check to see if the statistics for the different memory types have already been established
299 //
300 if (mMemoryTypeInformationInitialized) {
301 return;
302 }
303
304 //
305 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
306 //
307 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
308 //
309 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
310 //
311 Type = gMemoryTypeInformation[Index].Type;
312 if (Type < 0 || Type > EfiMaxMemoryType) {
313 continue;
314 }
315
316 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
317 //
318 // Allocate pages for the current memory type from the top of available memory
319 //
320 Status = CoreAllocatePages (
321 AllocateAnyPages,
322 Type,
323 gMemoryTypeInformation[Index].NumberOfPages,
324 &mMemoryTypeStatistics[Type].BaseAddress
325 );
326 if (EFI_ERROR (Status)) {
327 //
328 // If an error occurs allocating the pages for the current memory type, then
329 // free all the pages allocates for the previous memory types and return. This
330 // operation with be retied when/if more memory is added to the system
331 //
332 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
333 //
334 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
335 //
336 Type = gMemoryTypeInformation[FreeIndex].Type;
337 if (Type < 0 || Type > EfiMaxMemoryType) {
338 continue;
339 }
340
341 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
342 CoreFreePages (
343 mMemoryTypeStatistics[Type].BaseAddress,
344 gMemoryTypeInformation[FreeIndex].NumberOfPages
345 );
346 mMemoryTypeStatistics[Type].BaseAddress = 0;
347 mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;
348 }
349 }
350 return;
351 }
352
353 //
354 // Compute the address at the top of the current statistics
355 //
356 mMemoryTypeStatistics[Type].MaximumAddress =
357 mMemoryTypeStatistics[Type].BaseAddress +
358 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
359
360 //
361 // If the current base address is the lowest address so far, then update the default
362 // maximum address
363 //
364 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
365 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
366 }
367 }
368 }
369
370 //
371 // There was enough system memory for all the the memory types were allocated. So,
372 // those memory areas can be freed for future allocations, and all future memory
373 // allocations can occur within their respective bins
374 //
375 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
376 //
377 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
378 //
379 Type = gMemoryTypeInformation[Index].Type;
380 if (Type < 0 || Type > EfiMaxMemoryType) {
381 continue;
382 }
383
384 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
385 CoreFreePages (
386 mMemoryTypeStatistics[Type].BaseAddress,
387 gMemoryTypeInformation[Index].NumberOfPages
388 );
389 gMemoryTypeInformation[Index].NumberOfPages = 0;
390 }
391 }
392
393 //
394 // If the number of pages reserved for a memory type is 0, then all allocations for that type
395 // should be in the default range.
396 //
397 for (Type = 0; Type < EfiMaxMemoryType; Type++) {
398 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
399 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
400 mMemoryTypeStatistics[Type].InformationIndex = Index;
401 }
402 }
403 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
404 if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {
405 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
406 }
407 }
408
409 mMemoryTypeInformationInitialized = TRUE;
410 }
411
412
413 STATIC
414 VOID
415 CoreAddRange (
416 IN EFI_MEMORY_TYPE Type,
417 IN EFI_PHYSICAL_ADDRESS Start,
418 IN EFI_PHYSICAL_ADDRESS End,
419 IN UINT64 Attribute
420 )
421 /*++
422
423 Routine Description:
424
425 Internal function. Adds a ranges to the memory map.
426 The range must not already exist in the map.
427
428 Arguments:
429
430 Type - The type of memory range to add
431
432 Start - The starting address in the memory range
433 Must be paged aligned
434
435 End - The last address in the range
436 Must be the last byte of a page
437
438 Attribute - The attributes of the memory range to add
439
440 Returns:
441
442 None. The range is added to the memory map
443
444 --*/
445 {
446 LIST_ENTRY *Link;
447 MEMORY_MAP *Entry;
448
449 ASSERT ((Start & EFI_PAGE_MASK) == 0);
450 ASSERT (End > Start) ;
451
452 ASSERT_LOCKED (&gMemoryLock);
453
454 DEBUG ((EFI_D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
455
456 //
457 // Memory map being altered so updated key
458 //
459 mMemoryMapKey += 1;
460
461 //
462 // UEFI 2.0 added an event group for notificaiton on memory map changes.
463 // So we need to signal this Event Group every time the memory map changes.
464 // If we are in EFI 1.10 compatability mode no event groups will be
465 // found and nothing will happen we we call this function. These events
466 // will get signaled but since a lock is held around the call to this
467 // function the notificaiton events will only be called after this funciton
468 // returns and the lock is released.
469 //
470 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
471
472 //
473 // Look for adjoining memory descriptor
474 //
475
476 // Two memory descriptors can only be merged if they have the same Type
477 // and the same Attribute
478 //
479
480 Link = gMemoryMap.ForwardLink;
481 while (Link != &gMemoryMap) {
482 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
483 Link = Link->ForwardLink;
484
485 if (Entry->Type != Type) {
486 continue;
487 }
488
489 if (Entry->Attribute != Attribute) {
490 continue;
491 }
492
493 if (Entry->End + 1 == Start) {
494
495 Start = Entry->Start;
496 RemoveMemoryMapEntry (Entry);
497
498 } else if (Entry->Start == End + 1) {
499
500 End = Entry->End;
501 RemoveMemoryMapEntry (Entry);
502 }
503 }
504
505 //
506 // Add descriptor
507 //
508
509 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
510 mMapStack[mMapDepth].FromPool = FALSE;
511 mMapStack[mMapDepth].Type = Type;
512 mMapStack[mMapDepth].Start = Start;
513 mMapStack[mMapDepth].End = End;
514 mMapStack[mMapDepth].VirtualStart = 0;
515 mMapStack[mMapDepth].Attribute = Attribute;
516 InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
517
518 mMapDepth += 1;
519 ASSERT (mMapDepth < MAX_MAP_DEPTH);
520
521 return ;
522 }
523
524 STATIC
525 VOID
526 CoreFreeMemoryMapStack (
527 VOID
528 )
529 /*++
530
531 Routine Description:
532
533 Internal function. Moves any memory descriptors that are on the
534 temporary descriptor stack to heap.
535
536 Arguments:
537
538 None
539
540 Returns:
541
542 None
543
544 --*/
545 {
546 MEMORY_MAP *Entry;
547 MEMORY_MAP *Entry2;
548 LIST_ENTRY *Link2;
549
550 ASSERT_LOCKED (&gMemoryLock);
551
552 //
553 // If already freeing the map stack, then return
554 //
555 if (mFreeMapStack) {
556 return ;
557 }
558
559 //
560 // Move the temporary memory descriptor stack into pool
561 //
562 mFreeMapStack += 1;
563
564 while (mMapDepth) {
565
566 //
567 // Allocate memory for a entry
568 //
569 Entry = CoreAllocatePoolI (EfiRuntimeServicesData, sizeof(MEMORY_MAP));
570
571 ASSERT (Entry);
572
573 //
574 // Update to proper entry
575 //
576 mMapDepth -= 1;
577
578 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
579
580 //
581 // Move this entry to general pool
582 //
583 RemoveEntryList (&mMapStack[mMapDepth].Link);
584 mMapStack[mMapDepth].Link.ForwardLink = NULL;
585
586 CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
587 Entry->FromPool = TRUE;
588
589 //
590 // Find insertion location
591 //
592 for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
593 Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
594 if (Entry2->FromPool && Entry2->Start > Entry->Start) {
595 break;
596 }
597 }
598
599 InsertTailList (Link2, &Entry->Link);
600
601 } else {
602
603 //
604 // It was removed, don't move it
605 //
606 CoreFreePoolI (Entry);
607
608 }
609 }
610
611 mFreeMapStack -= 1;
612 }
613
614 STATIC
615 VOID
616 RemoveMemoryMapEntry (
617 MEMORY_MAP *Entry
618 )
619 /*++
620
621 Routine Description:
622
623 Internal function. Removes a descriptor entry.
624
625 Arguments:
626
627 Entry - The entry to remove
628
629 Returns:
630
631 None
632
633 --*/
634 {
635 RemoveEntryList (&Entry->Link);
636 Entry->Link.ForwardLink = NULL;
637
638 if (Entry->FromPool) {
639 CoreFreePoolI (Entry);
640 }
641 }
642
643
644 STATIC
645 EFI_STATUS
646 CoreConvertPages (
647 IN UINT64 Start,
648 IN UINT64 NumberOfPages,
649 IN EFI_MEMORY_TYPE NewType
650 )
651 /*++
652
653 Routine Description:
654
655 Internal function. Converts a memory range to the specified type.
656 The range must exist in the memory map.
657
658 Arguments:
659
660 Start - The first address of the range
661 Must be page aligned
662
663 NumberOfPages - The number of pages to convert
664
665 NewType - The new type for the memory range
666
667 Returns:
668
669 EFI_INVALID_PARAMETER - Invalid parameter
670
671 EFI_NOT_FOUND - Could not find a descriptor cover the specified range
672 or convertion not allowed.
673
674 EFI_SUCCESS - Successfully converts the memory range to the specified type.
675
676 --*/
677 {
678
679 UINT64 NumberOfBytes;
680 UINT64 End;
681 UINT64 RangeEnd;
682 UINT64 Attribute;
683 LIST_ENTRY *Link;
684 MEMORY_MAP *Entry;
685
686 Entry = NULL;
687 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
688 End = Start + NumberOfBytes - 1;
689
690 ASSERT (NumberOfPages);
691 ASSERT ((Start & EFI_PAGE_MASK) == 0);
692 ASSERT (End > Start) ;
693 ASSERT_LOCKED (&gMemoryLock);
694
695 if (NumberOfPages == 0 || (Start & EFI_PAGE_MASK ) || (Start > (Start + NumberOfBytes))) {
696 return EFI_INVALID_PARAMETER;
697 }
698
699 //
700 // Convert the entire range
701 //
702
703 while (Start < End) {
704
705 //
706 // Find the entry that the covers the range
707 //
708 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
709 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
710
711 if (Entry->Start <= Start && Entry->End > Start) {
712 break;
713 }
714 }
715
716 if (Link == &gMemoryMap) {
717 DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
718 return EFI_NOT_FOUND;
719 }
720
721 //
722 // Convert range to the end, or to the end of the descriptor
723 // if that's all we've got
724 //
725 RangeEnd = End;
726 if (Entry->End < End) {
727 RangeEnd = Entry->End;
728 }
729
730 DEBUG ((EFI_D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));
731
732 //
733 // Debug code - verify conversion is allowed
734 //
735 if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
736 DEBUG ((EFI_D_ERROR , "ConvertPages: Incompatible memory types\n"));
737 return EFI_NOT_FOUND;
738 }
739
740 //
741 // Update counters for the number of pages allocated to each memory type
742 //
743 if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {
744 if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress &&
745 Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {
746 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
747 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
748 } else {
749 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
750 }
751 }
752 }
753
754 if (NewType >= 0 && NewType < EfiMaxMemoryType) {
755 if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {
756 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
757 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages >
758 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
759 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
760 }
761 }
762 }
763
764 //
765 // Pull range out of descriptor
766 //
767 if (Entry->Start == Start) {
768
769 //
770 // Clip start
771 //
772 Entry->Start = RangeEnd + 1;
773
774 } else if (Entry->End == RangeEnd) {
775
776 //
777 // Clip end
778 //
779 Entry->End = Start - 1;
780
781 } else {
782
783 //
784 // Pull it out of the center, clip current
785 //
786
787 //
788 // Add a new one
789 //
790 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
791 mMapStack[mMapDepth].FromPool = FALSE;
792 mMapStack[mMapDepth].Type = Entry->Type;
793 mMapStack[mMapDepth].Start = RangeEnd+1;
794 mMapStack[mMapDepth].End = Entry->End;
795
796 //
797 // Inherit Attribute from the Memory Descriptor that is being clipped
798 //
799 mMapStack[mMapDepth].Attribute = Entry->Attribute;
800
801 Entry->End = Start - 1;
802 ASSERT (Entry->Start < Entry->End);
803
804 Entry = &mMapStack[mMapDepth];
805 InsertTailList (&gMemoryMap, &Entry->Link);
806
807 mMapDepth += 1;
808 ASSERT (mMapDepth < MAX_MAP_DEPTH);
809 }
810
811 //
812 // The new range inherits the same Attribute as the Entry
813 //it is being cut out of
814 //
815 Attribute = Entry->Attribute;
816
817 //
818 // If the descriptor is empty, then remove it from the map
819 //
820 if (Entry->Start == Entry->End + 1) {
821 RemoveMemoryMapEntry (Entry);
822 Entry = NULL;
823 }
824
825 //
826 // Add our new range in
827 //
828 CoreAddRange (NewType, Start, RangeEnd, Attribute);
829
830 //
831 // Move any map descriptor stack to general pool
832 //
833 CoreFreeMemoryMapStack ();
834
835 //
836 // Bump the starting address, and convert the next range
837 //
838 Start = RangeEnd + 1;
839 }
840
841 //
842 // Converted the whole range, done
843 //
844
845 return EFI_SUCCESS;
846 }
847
848
849 STATIC
850 UINT64
851 CoreFindFreePagesI (
852 IN UINT64 MaxAddress,
853 IN UINT64 NumberOfPages,
854 IN EFI_MEMORY_TYPE NewType,
855 IN UINTN Alignment
856 )
857 /*++
858
859 Routine Description:
860
861 Internal function. Finds a consecutive free page range below
862 the requested address.
863
864 Arguments:
865
866 MaxAddress - The address that the range must be below
867
868 NumberOfPages - Number of pages needed
869
870 NewType - The type of memory the range is going to be turned into
871
872 Alignment - Bits to align with
873
874 Returns:
875
876 The base address of the range, or 0 if the range was not found
877
878 --*/
879 {
880 UINT64 NumberOfBytes;
881 UINT64 Target;
882 UINT64 DescStart;
883 UINT64 DescEnd;
884 UINT64 DescNumberOfBytes;
885 LIST_ENTRY *Link;
886 MEMORY_MAP *Entry;
887
888 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
889 return 0;
890 }
891
892 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
893
894 //
895 // If MaxAddress is not aligned to the end of a page
896 //
897
898 //
899 // Change MaxAddress to be 1 page lower
900 //
901 MaxAddress -= (EFI_PAGE_MASK + 1);
902
903 //
904 // Set MaxAddress to a page boundary
905 //
906 MaxAddress &= ~EFI_PAGE_MASK;
907
908 //
909 // Set MaxAddress to end of the page
910 //
911 MaxAddress |= EFI_PAGE_MASK;
912 }
913
914 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
915 Target = 0;
916
917 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
918 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
919
920 //
921 // If it's not a free entry, don't bother with it
922 //
923 if (Entry->Type != EfiConventionalMemory) {
924 continue;
925 }
926
927 DescStart = Entry->Start;
928 DescEnd = Entry->End;
929
930 //
931 // If desc is past max allowed address, skip it
932 //
933 if (DescStart >= MaxAddress) {
934 continue;
935 }
936
937 //
938 // If desc ends past max allowed address, clip the end
939 //
940 if (DescEnd >= MaxAddress) {
941 DescEnd = MaxAddress;
942 }
943
944 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
945
946 //
947 // Compute the number of bytes we can used from this
948 // descriptor, and see it's enough to satisfy the request
949 //
950 DescNumberOfBytes = DescEnd - DescStart + 1;
951
952 if (DescNumberOfBytes >= NumberOfBytes) {
953
954 //
955 // If this is the best match so far remember it
956 //
957 if (DescEnd > Target) {
958 Target = DescEnd;
959 }
960 }
961 }
962
963 //
964 // If this is a grow down, adjust target to be the allocation base
965 //
966 Target -= NumberOfBytes - 1;
967
968 //
969 // If we didn't find a match, return 0
970 //
971 if ((Target & EFI_PAGE_MASK) != 0) {
972 return 0;
973 }
974
975 return Target;
976 }
977
978 STATIC
979 UINT64
980 FindFreePages (
981 IN UINT64 MaxAddress,
982 IN UINT64 NoPages,
983 IN EFI_MEMORY_TYPE NewType,
984 IN UINTN Alignment
985 )
986 /*++
987
988 Routine Description:
989
990 Internal function. Finds a consecutive free page range below
991 the requested address
992
993 Arguments:
994
995 MaxAddress - The address that the range must be below
996
997 NoPages - Number of pages needed
998
999 NewType - The type of memory the range is going to be turned into
1000
1001 Alignment - Bits to align with
1002
1003 Returns:
1004
1005 The base address of the range, or 0 if the range was not found.
1006
1007 --*/
1008 {
1009 UINT64 NewMaxAddress;
1010 UINT64 Start;
1011
1012 NewMaxAddress = MaxAddress;
1013
1014 if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
1015 NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress;
1016 } else {
1017 if (NewMaxAddress > mDefaultMaximumAddress) {
1018 NewMaxAddress = mDefaultMaximumAddress;
1019 }
1020 }
1021
1022 Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);
1023 if (!Start) {
1024 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
1025 if (!Start) {
1026 //
1027 // Here means there may be no enough memory to use, so try to go through
1028 // all the memory descript to promote the untested memory directly
1029 //
1030 PromoteMemoryResource ();
1031
1032 //
1033 // Allocate memory again after the memory resource re-arranged
1034 //
1035 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
1036 }
1037 }
1038
1039 return Start;
1040 }
1041
1042
1043 EFI_STATUS
1044 EFIAPI
1045 CoreAllocatePages (
1046 IN EFI_ALLOCATE_TYPE Type,
1047 IN EFI_MEMORY_TYPE MemoryType,
1048 IN UINTN NumberOfPages,
1049 IN OUT EFI_PHYSICAL_ADDRESS *Memory
1050 )
1051 /*++
1052
1053 Routine Description:
1054
1055 Allocates pages from the memory map.
1056
1057 Arguments:
1058
1059 Type - The type of allocation to perform
1060
1061 MemoryType - The type of memory to turn the allocated pages into
1062
1063 NumberOfPages - The number of pages to allocate
1064
1065 Memory - A pointer to receive the base allocated memory address
1066
1067 Returns:
1068
1069 Status. On success, Memory is filled in with the base address allocated
1070
1071 EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec.
1072
1073 EFI_NOT_FOUND - Could not allocate pages match the requirement.
1074
1075 EFI_OUT_OF_RESOURCES - No enough pages to allocate.
1076
1077 EFI_SUCCESS - Pages successfully allocated.
1078
1079 --*/
1080 {
1081 EFI_STATUS Status;
1082 UINT64 Start;
1083 UINT64 MaxAddress;
1084 UINTN Alignment;
1085
1086 if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) {
1087 return EFI_INVALID_PARAMETER;
1088 }
1089
1090 if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||
1091 MemoryType == EfiConventionalMemory) {
1092 return EFI_INVALID_PARAMETER;
1093 }
1094
1095 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1096
1097 if (MemoryType == EfiACPIReclaimMemory ||
1098 MemoryType == EfiACPIMemoryNVS ||
1099 MemoryType == EfiRuntimeServicesCode ||
1100 MemoryType == EfiRuntimeServicesData) {
1101
1102 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1103 }
1104
1105 if (Type == AllocateAddress) {
1106 if ((*Memory & (Alignment - 1)) != 0) {
1107 return EFI_NOT_FOUND;
1108 }
1109 }
1110
1111 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1112 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1113
1114 //
1115 // If this is for below a particular address, then
1116 //
1117 Start = *Memory;
1118
1119 //
1120 // The max address is the max natively addressable address for the processor
1121 //
1122 MaxAddress = EFI_MAX_ADDRESS;
1123
1124 if (Type == AllocateMaxAddress) {
1125 MaxAddress = Start;
1126 }
1127
1128 CoreAcquireMemoryLock ();
1129
1130 //
1131 // If not a specific address, then find an address to allocate
1132 //
1133 if (Type != AllocateAddress) {
1134 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
1135 if (Start == 0) {
1136 Status = EFI_OUT_OF_RESOURCES;
1137 goto Done;
1138 }
1139 }
1140
1141 //
1142 // Convert pages from FreeMemory to the requested type
1143 //
1144 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
1145
1146 Done:
1147 CoreReleaseMemoryLock ();
1148
1149 if (!EFI_ERROR (Status)) {
1150 *Memory = Start;
1151 }
1152
1153 return Status;
1154 }
1155
1156
1157
1158
1159 EFI_STATUS
1160 EFIAPI
1161 CoreFreePages (
1162 IN EFI_PHYSICAL_ADDRESS Memory,
1163 IN UINTN NumberOfPages
1164 )
1165 /*++
1166
1167 Routine Description:
1168
1169 Frees previous allocated pages.
1170
1171 Arguments:
1172
1173 Memory - Base address of memory being freed
1174
1175 NumberOfPages - The number of pages to free
1176
1177 Returns:
1178
1179 EFI_NOT_FOUND - Could not find the entry that covers the range
1180
1181 EFI_INVALID_PARAMETER - Address not aligned
1182
1183 EFI_SUCCESS -Pages successfully freed.
1184
1185 --*/
1186 {
1187 EFI_STATUS Status;
1188 LIST_ENTRY *Link;
1189 MEMORY_MAP *Entry;
1190 UINTN Alignment;
1191
1192 //
1193 // Free the range
1194 //
1195 CoreAcquireMemoryLock ();
1196
1197 //
1198 // Find the entry that the covers the range
1199 //
1200 Entry = NULL;
1201 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1202 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1203 if (Entry->Start <= Memory && Entry->End > Memory) {
1204 break;
1205 }
1206 }
1207 if (Link == &gMemoryMap) {
1208 CoreReleaseMemoryLock ();
1209 return EFI_NOT_FOUND;
1210 }
1211
1212 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1213
1214 if (Entry->Type == EfiACPIReclaimMemory ||
1215 Entry->Type == EfiACPIMemoryNVS ||
1216 Entry->Type == EfiRuntimeServicesCode ||
1217 Entry->Type == EfiRuntimeServicesData) {
1218
1219 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1220
1221 }
1222
1223 if ((Memory & (Alignment - 1)) != 0) {
1224 CoreReleaseMemoryLock ();
1225 return EFI_INVALID_PARAMETER;
1226 }
1227
1228 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1229 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1230
1231 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1232
1233 CoreReleaseMemoryLock ();
1234
1235 if (EFI_ERROR (Status)) {
1236 return Status;
1237 }
1238
1239 //
1240 // Destroy the contents
1241 //
1242 if (Memory < EFI_MAX_ADDRESS) {
1243 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);
1244 }
1245
1246 return Status;
1247 }
1248
1249
1250
1251 EFI_STATUS
1252 EFIAPI
1253 CoreGetMemoryMap (
1254 IN OUT UINTN *MemoryMapSize,
1255 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1256 OUT UINTN *MapKey,
1257 OUT UINTN *DescriptorSize,
1258 OUT UINT32 *DescriptorVersion
1259 )
1260 /*++
1261
1262 Routine Description:
1263
1264 This function returns a copy of the current memory map. The map is an array of
1265 memory descriptors, each of which describes a contiguous block of memory.
1266
1267 Arguments:
1268
1269 MemoryMapSize - A pointer to the size, in bytes, of the MemoryMap buffer. On
1270 input, this is the size of the buffer allocated by the caller.
1271 On output, it is the size of the buffer returned by the firmware
1272 if the buffer was large enough, or the size of the buffer needed
1273 to contain the map if the buffer was too small.
1274 MemoryMap - A pointer to the buffer in which firmware places the current memory map.
1275 MapKey - A pointer to the location in which firmware returns the key for the
1276 current memory map.
1277 DescriptorSize - A pointer to the location in which firmware returns the size, in
1278 bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1279 DescriptorVersion - A pointer to the location in which firmware returns the version
1280 number associated with the EFI_MEMORY_DESCRIPTOR.
1281
1282 Returns:
1283
1284 EFI_SUCCESS - The memory map was returned in the MemoryMap buffer.
1285 EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size
1286 needed to hold the memory map is returned in MemoryMapSize.
1287 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
1288
1289 --*/
1290 {
1291 EFI_STATUS Status;
1292 UINTN Size;
1293 UINTN BufferSize;
1294 UINTN NumberOfRuntimeEntries;
1295 LIST_ENTRY *Link;
1296 MEMORY_MAP *Entry;
1297 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1298
1299 //
1300 // Make sure the parameters are valid
1301 //
1302 if (MemoryMapSize == NULL) {
1303 return EFI_INVALID_PARAMETER;
1304 }
1305
1306 CoreAcquireGcdMemoryLock ();
1307
1308 //
1309 // Count the number of Reserved and MMIO entries that are marked for runtime use
1310 //
1311 NumberOfRuntimeEntries = 0;
1312 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1313 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1314 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1315 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
1316 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
1317 NumberOfRuntimeEntries++;
1318 }
1319 }
1320 }
1321
1322 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1323
1324 //
1325 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1326 // prevent people from having pointer math bugs in their code.
1327 // now you have to use *DescriptorSize to make things work.
1328 //
1329 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1330
1331 if (DescriptorSize != NULL) {
1332 *DescriptorSize = Size;
1333 }
1334
1335 if (DescriptorVersion != NULL) {
1336 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1337 }
1338
1339 CoreAcquireMemoryLock ();
1340
1341 //
1342 // Compute the buffer size needed to fit the entire map
1343 //
1344 BufferSize = Size * NumberOfRuntimeEntries;
1345 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1346 BufferSize += Size;
1347 }
1348
1349 if (*MemoryMapSize < BufferSize) {
1350 Status = EFI_BUFFER_TOO_SMALL;
1351 goto Done;
1352 }
1353
1354 if (MemoryMap == NULL) {
1355 Status = EFI_INVALID_PARAMETER;
1356 goto Done;
1357 }
1358
1359 //
1360 // Build the map
1361 //
1362 ZeroMem (MemoryMap, Size);
1363 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1364 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1365 ASSERT (Entry->VirtualStart == 0);
1366
1367 MemoryMap->Type = Entry->Type;
1368 MemoryMap->PhysicalStart = Entry->Start;
1369 MemoryMap->VirtualStart = Entry->VirtualStart;
1370 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1371
1372 switch (Entry->Type) {
1373 case EfiRuntimeServicesCode:
1374 case EfiRuntimeServicesData:
1375 case EfiPalCode:
1376 MemoryMap->Attribute = Entry->Attribute | EFI_MEMORY_RUNTIME;
1377 break;
1378
1379 default:
1380 MemoryMap->Attribute = Entry->Attribute;
1381 break;
1382 }
1383
1384 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
1385 }
1386
1387 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1388 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1389 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1390 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
1391 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
1392
1393 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
1394 MemoryMap->VirtualStart = 0;
1395 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
1396 MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;
1397
1398 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {
1399 MemoryMap->Type = EfiReservedMemoryType;
1400 } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1401 if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1402 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1403 } else {
1404 MemoryMap->Type = EfiMemoryMappedIO;
1405 }
1406 }
1407
1408 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
1409 }
1410 }
1411 }
1412
1413 Status = EFI_SUCCESS;
1414
1415 Done:
1416
1417 CoreReleaseMemoryLock ();
1418
1419 CoreReleaseGcdMemoryLock ();
1420
1421 //
1422 // Update the map key finally
1423 //
1424 if (MapKey != NULL) {
1425 *MapKey = mMemoryMapKey;
1426 }
1427
1428 *MemoryMapSize = BufferSize;
1429
1430 return Status;
1431 }
1432
1433 VOID *
1434 CoreAllocatePoolPages (
1435 IN EFI_MEMORY_TYPE PoolType,
1436 IN UINTN NumberOfPages,
1437 IN UINTN Alignment
1438 )
1439 /*++
1440
1441 Routine Description:
1442
1443 Internal function. Used by the pool functions to allocate pages
1444 to back pool allocation requests.
1445
1446 Arguments:
1447
1448 PoolType - The type of memory for the new pool pages
1449
1450 NumberOfPages - No of pages to allocate
1451
1452 Alignment - Bits to align.
1453
1454 Returns:
1455
1456 The allocated memory, or NULL
1457
1458 --*/
1459 {
1460 EFI_STATUS Status;
1461 UINT64 Start;
1462
1463 //
1464 // Find the pages to convert
1465 //
1466 Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
1467
1468 //
1469 // Convert it to boot services data
1470 //
1471 if (Start == 0) {
1472 DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));
1473 } else {
1474 Status = CoreConvertPages (Start, NumberOfPages, PoolType);
1475 }
1476
1477 return (VOID *)(UINTN)Start;
1478 }
1479
1480 VOID
1481 CoreFreePoolPages (
1482 IN EFI_PHYSICAL_ADDRESS Memory,
1483 IN UINTN NumberOfPages
1484 )
1485 /*++
1486
1487 Routine Description:
1488
1489 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1490
1491 Arguments:
1492
1493 Memory - The base address to free
1494
1495 NumberOfPages - The number of pages to free
1496
1497 Returns:
1498
1499 None
1500
1501 --*/
1502 {
1503 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1504 }
1505
1506
1507 EFI_STATUS
1508 CoreTerminateMemoryMap (
1509 IN UINTN MapKey
1510 )
1511 /*++
1512
1513 Routine Description:
1514
1515 Make sure the memory map is following all the construction rules,
1516 it is the last time to check memory map error before exit boot services.
1517
1518 Arguments:
1519
1520 MapKey - Memory map key
1521
1522 Returns:
1523
1524 EFI_INVALID_PARAMETER - Memory map not consistent with construction rules.
1525
1526 EFI_SUCCESS - Valid memory map.
1527
1528 --*/
1529 {
1530 EFI_STATUS Status;
1531 LIST_ENTRY *Link;
1532 MEMORY_MAP *Entry;
1533
1534 Status = EFI_SUCCESS;
1535
1536 CoreAcquireMemoryLock ();
1537
1538 if (MapKey == mMemoryMapKey) {
1539
1540 //
1541 // Make sure the memory map is following all the construction rules
1542 // This is the last chance we will be able to display any messages on
1543 // the console devices.
1544 //
1545
1546 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1547 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1548 if (Entry->Attribute & EFI_MEMORY_RUNTIME) {
1549 if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {
1550 DEBUG((EFI_D_ERROR, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1551 CoreReleaseMemoryLock ();
1552 return EFI_INVALID_PARAMETER;
1553 }
1554 if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
1555 DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1556 CoreReleaseMemoryLock ();
1557 return EFI_INVALID_PARAMETER;
1558 }
1559 if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
1560 DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1561 CoreReleaseMemoryLock ();
1562 return EFI_INVALID_PARAMETER;
1563 }
1564 }
1565 }
1566
1567 //
1568 // The map key they gave us matches what we expect. Fall through and
1569 // return success. In an ideal world we would clear out all of
1570 // EfiBootServicesCode and EfiBootServicesData. However this function
1571 // is not the last one called by ExitBootServices(), so we have to
1572 // preserve the memory contents.
1573 //
1574 } else {
1575 Status = EFI_INVALID_PARAMETER;
1576 }
1577
1578 CoreReleaseMemoryLock ();
1579
1580 return Status;
1581 }
1582
1583
1584
1585
1586
1587
1588
1589