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