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