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