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