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