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