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