]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg/DxeCore: Fix issues in Heap Guard
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
1 /** @file
2 UEFI Memory page management functions.
3
4 Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
5 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 #include "Imem.h"
17 #include "HeapGuard.h"
18
19 //
20 // Entry for tracking the memory regions for each memory type to coalesce similar 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_STATISTICS;
31
32 //
33 // MemoryMap - The current memory map
34 //
35 UINTN mMemoryMapKey = 0;
36
37 #define MAX_MAP_DEPTH 6
38
39 ///
40 /// mMapDepth - depth of new descriptor stack
41 ///
42 UINTN mMapDepth = 0;
43 ///
44 /// mMapStack - space to use as temp storage to build new map descriptors
45 ///
46 MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
47 UINTN mFreeMapStack = 0;
48 ///
49 /// This list maintain the free memory map list
50 ///
51 LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
52 BOOLEAN mMemoryTypeInformationInitialized = FALSE;
53
54 EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
55 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
56 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
57 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
58 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
59 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
60 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
61 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
62 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
63 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
64 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
65 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
66 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
67 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
68 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
69 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory
70 { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
71 };
72
73 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ADDRESS;
74 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ADDRESS;
75
76 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
77 { EfiReservedMemoryType, 0 },
78 { EfiLoaderCode, 0 },
79 { EfiLoaderData, 0 },
80 { EfiBootServicesCode, 0 },
81 { EfiBootServicesData, 0 },
82 { EfiRuntimeServicesCode, 0 },
83 { EfiRuntimeServicesData, 0 },
84 { EfiConventionalMemory, 0 },
85 { EfiUnusableMemory, 0 },
86 { EfiACPIReclaimMemory, 0 },
87 { EfiACPIMemoryNVS, 0 },
88 { EfiMemoryMappedIO, 0 },
89 { EfiMemoryMappedIOPortSpace, 0 },
90 { EfiPalCode, 0 },
91 { EfiPersistentMemory, 0 },
92 { EfiMaxMemoryType, 0 }
93 };
94 //
95 // Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
96 // and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
97 // address assigned by DXE core.
98 //
99 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;
100
101 /**
102 Enter critical section by gaining lock on gMemoryLock.
103
104 **/
105 VOID
106 CoreAcquireMemoryLock (
107 VOID
108 )
109 {
110 CoreAcquireLock (&gMemoryLock);
111 }
112
113
114
115 /**
116 Exit critical section by releasing lock on gMemoryLock.
117
118 **/
119 VOID
120 CoreReleaseMemoryLock (
121 VOID
122 )
123 {
124 CoreReleaseLock (&gMemoryLock);
125 }
126
127
128
129
130 /**
131 Internal function. Removes a descriptor entry.
132
133 @param Entry The entry to remove
134
135 **/
136 VOID
137 RemoveMemoryMapEntry (
138 IN OUT MEMORY_MAP *Entry
139 )
140 {
141 RemoveEntryList (&Entry->Link);
142 Entry->Link.ForwardLink = NULL;
143
144 if (Entry->FromPages) {
145 //
146 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
147 //
148 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
149 }
150 }
151
152 /**
153 Internal function. Adds a ranges to the memory map.
154 The range must not already exist in the map.
155
156 @param Type The type of memory range to add
157 @param Start The starting address in the memory range Must be
158 paged aligned
159 @param End The last address in the range Must be the last
160 byte of a page
161 @param Attribute The attributes of the memory range to add
162
163 **/
164 VOID
165 CoreAddRange (
166 IN EFI_MEMORY_TYPE Type,
167 IN EFI_PHYSICAL_ADDRESS Start,
168 IN EFI_PHYSICAL_ADDRESS End,
169 IN UINT64 Attribute
170 )
171 {
172 LIST_ENTRY *Link;
173 MEMORY_MAP *Entry;
174
175 ASSERT ((Start & EFI_PAGE_MASK) == 0);
176 ASSERT (End > Start) ;
177
178 ASSERT_LOCKED (&gMemoryLock);
179
180 DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
181
182 //
183 // If memory of type EfiConventionalMemory is being added that includes the page
184 // starting at address 0, then zero the page starting at address 0. This has
185 // two benifits. It helps find NULL pointer bugs and it also maximizes
186 // compatibility with operating systems that may evaluate memory in this page
187 // for legacy data structures. If memory of any other type is added starting
188 // at address 0, then do not zero the page at address 0 because the page is being
189 // used for other purposes.
190 //
191 if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) {
192 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
193 SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);
194 }
195 }
196
197 //
198 // Memory map being altered so updated key
199 //
200 mMemoryMapKey += 1;
201
202 //
203 // UEFI 2.0 added an event group for notificaiton on memory map changes.
204 // So we need to signal this Event Group every time the memory map changes.
205 // If we are in EFI 1.10 compatability mode no event groups will be
206 // found and nothing will happen we we call this function. These events
207 // will get signaled but since a lock is held around the call to this
208 // function the notificaiton events will only be called after this function
209 // returns and the lock is released.
210 //
211 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
212
213 //
214 // Look for adjoining memory descriptor
215 //
216
217 // Two memory descriptors can only be merged if they have the same Type
218 // and the same Attribute
219 //
220
221 Link = gMemoryMap.ForwardLink;
222 while (Link != &gMemoryMap) {
223 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
224 Link = Link->ForwardLink;
225
226 if (Entry->Type != Type) {
227 continue;
228 }
229
230 if (Entry->Attribute != Attribute) {
231 continue;
232 }
233
234 if (Entry->End + 1 == Start) {
235
236 Start = Entry->Start;
237 RemoveMemoryMapEntry (Entry);
238
239 } else if (Entry->Start == End + 1) {
240
241 End = Entry->End;
242 RemoveMemoryMapEntry (Entry);
243 }
244 }
245
246 //
247 // Add descriptor
248 //
249
250 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
251 mMapStack[mMapDepth].FromPages = FALSE;
252 mMapStack[mMapDepth].Type = Type;
253 mMapStack[mMapDepth].Start = Start;
254 mMapStack[mMapDepth].End = End;
255 mMapStack[mMapDepth].VirtualStart = 0;
256 mMapStack[mMapDepth].Attribute = Attribute;
257 InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
258
259 mMapDepth += 1;
260 ASSERT (mMapDepth < MAX_MAP_DEPTH);
261
262 return ;
263 }
264
265 /**
266 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
267 If the list is emtry, then allocate a new page to refuel the list.
268 Please Note this algorithm to allocate the memory map descriptor has a property
269 that the memory allocated for memory entries always grows, and will never really be freed
270 For example, if the current boot uses 2000 memory map entries at the maximum point, but
271 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
272 memory map entries is still allocated from EfiBootServicesMemory.
273
274
275 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
276
277 **/
278 MEMORY_MAP *
279 AllocateMemoryMapEntry (
280 VOID
281 )
282 {
283 MEMORY_MAP* FreeDescriptorEntries;
284 MEMORY_MAP* Entry;
285 UINTN Index;
286
287 if (IsListEmpty (&mFreeMemoryMapEntryList)) {
288 //
289 // The list is empty, to allocate one page to refuel the list
290 //
291 FreeDescriptorEntries = CoreAllocatePoolPages (
292 EfiBootServicesData,
293 EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),
294 DEFAULT_PAGE_ALLOCATION_GRANULARITY,
295 FALSE
296 );
297 if (FreeDescriptorEntries != NULL) {
298 //
299 // Enque the free memmory map entries into the list
300 //
301 for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) {
302 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
303 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
304 }
305 } else {
306 return NULL;
307 }
308 }
309 //
310 // dequeue the first descriptor from the list
311 //
312 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
313 RemoveEntryList (&Entry->Link);
314
315 return Entry;
316 }
317
318
319 /**
320 Internal function. Moves any memory descriptors that are on the
321 temporary descriptor stack to heap.
322
323 **/
324 VOID
325 CoreFreeMemoryMapStack (
326 VOID
327 )
328 {
329 MEMORY_MAP *Entry;
330 MEMORY_MAP *Entry2;
331 LIST_ENTRY *Link2;
332
333 ASSERT_LOCKED (&gMemoryLock);
334
335 //
336 // If already freeing the map stack, then return
337 //
338 if (mFreeMapStack != 0) {
339 return ;
340 }
341
342 //
343 // Move the temporary memory descriptor stack into pool
344 //
345 mFreeMapStack += 1;
346
347 while (mMapDepth != 0) {
348 //
349 // Deque an memory map entry from mFreeMemoryMapEntryList
350 //
351 Entry = AllocateMemoryMapEntry ();
352
353 ASSERT (Entry);
354
355 //
356 // Update to proper entry
357 //
358 mMapDepth -= 1;
359
360 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
361
362 //
363 // Move this entry to general memory
364 //
365 RemoveEntryList (&mMapStack[mMapDepth].Link);
366 mMapStack[mMapDepth].Link.ForwardLink = NULL;
367
368 CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
369 Entry->FromPages = TRUE;
370
371 //
372 // Find insertion location
373 //
374 for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
375 Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
376 if (Entry2->FromPages && Entry2->Start > Entry->Start) {
377 break;
378 }
379 }
380
381 InsertTailList (Link2, &Entry->Link);
382
383 } else {
384 //
385 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
386 // so here no need to move it to memory.
387 //
388 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
389 }
390 }
391
392 mFreeMapStack -= 1;
393 }
394
395 /**
396 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
397
398 **/
399 BOOLEAN
400 PromoteMemoryResource (
401 VOID
402 )
403 {
404 LIST_ENTRY *Link;
405 EFI_GCD_MAP_ENTRY *Entry;
406 BOOLEAN Promoted;
407
408 DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
409
410 CoreAcquireGcdMemoryLock ();
411
412 Promoted = FALSE;
413 Link = mGcdMemorySpaceMap.ForwardLink;
414 while (Link != &mGcdMemorySpaceMap) {
415
416 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
417
418 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
419 Entry->EndAddress < MAX_ADDRESS &&
420 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
421 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
422 //
423 // Update the GCD map
424 //
425 if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
426 Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
427 } else {
428 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
429 }
430 Entry->Capabilities |= EFI_MEMORY_TESTED;
431 Entry->ImageHandle = gDxeCoreImageHandle;
432 Entry->DeviceHandle = NULL;
433
434 //
435 // Add to allocable system memory resource
436 //
437
438 CoreAddRange (
439 EfiConventionalMemory,
440 Entry->BaseAddress,
441 Entry->EndAddress,
442 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
443 );
444 CoreFreeMemoryMapStack ();
445
446 Promoted = TRUE;
447 }
448
449 Link = Link->ForwardLink;
450 }
451
452 CoreReleaseGcdMemoryLock ();
453
454 return Promoted;
455 }
456 /**
457 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
458 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
459 size of boot time and runtime code.
460
461 **/
462 VOID
463 CoreLoadingFixedAddressHook (
464 VOID
465 )
466 {
467 UINT32 RuntimeCodePageNumber;
468 UINT32 BootTimeCodePageNumber;
469 EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
470 EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
471 EFI_STATUS Status;
472
473 //
474 // Make sure these 2 areas are not initialzied.
475 //
476 if (!gLoadFixedAddressCodeMemoryReady) {
477 RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
478 BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
479 RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
480 BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
481 //
482 // Try to allocate runtime memory.
483 //
484 Status = CoreAllocatePages (
485 AllocateAddress,
486 EfiRuntimeServicesCode,
487 RuntimeCodePageNumber,
488 &RuntimeCodeBase
489 );
490 if (EFI_ERROR(Status)) {
491 //
492 // Runtime memory allocation failed
493 //
494 return;
495 }
496 //
497 // Try to allocate boot memory.
498 //
499 Status = CoreAllocatePages (
500 AllocateAddress,
501 EfiBootServicesCode,
502 BootTimeCodePageNumber,
503 &BootTimeCodeBase
504 );
505 if (EFI_ERROR(Status)) {
506 //
507 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
508 // new memory range is installed.
509 //
510 CoreFreePages (
511 RuntimeCodeBase,
512 RuntimeCodePageNumber
513 );
514 return;
515 }
516 gLoadFixedAddressCodeMemoryReady = TRUE;
517 }
518 return;
519 }
520
521 /**
522 Called to initialize the memory map and add descriptors to
523 the current descriptor list.
524 The first descriptor that is added must be general usable
525 memory as the addition allocates heap.
526
527 @param Type The type of memory to add
528 @param Start The starting address in the memory range Must be
529 page aligned
530 @param NumberOfPages The number of pages in the range
531 @param Attribute Attributes of the memory to add
532
533 @return None. The range is added to the memory map
534
535 **/
536 VOID
537 CoreAddMemoryDescriptor (
538 IN EFI_MEMORY_TYPE Type,
539 IN EFI_PHYSICAL_ADDRESS Start,
540 IN UINT64 NumberOfPages,
541 IN UINT64 Attribute
542 )
543 {
544 EFI_PHYSICAL_ADDRESS End;
545 EFI_STATUS Status;
546 UINTN Index;
547 UINTN FreeIndex;
548
549 if ((Start & EFI_PAGE_MASK) != 0) {
550 return;
551 }
552
553 if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) {
554 return;
555 }
556 CoreAcquireMemoryLock ();
557 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
558 CoreAddRange (Type, Start, End, Attribute);
559 CoreFreeMemoryMapStack ();
560 CoreReleaseMemoryLock ();
561
562 ApplyMemoryProtectionPolicy (EfiMaxMemoryType, Type, Start,
563 LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT));
564
565 //
566 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
567 //
568 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
569 CoreLoadingFixedAddressHook();
570 }
571
572 //
573 // Check to see if the statistics for the different memory types have already been established
574 //
575 if (mMemoryTypeInformationInitialized) {
576 return;
577 }
578
579
580 //
581 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
582 //
583 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
584 //
585 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
586 //
587 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
588 if ((UINT32)Type > EfiMaxMemoryType) {
589 continue;
590 }
591 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
592 //
593 // Allocate pages for the current memory type from the top of available memory
594 //
595 Status = CoreAllocatePages (
596 AllocateAnyPages,
597 Type,
598 gMemoryTypeInformation[Index].NumberOfPages,
599 &mMemoryTypeStatistics[Type].BaseAddress
600 );
601 if (EFI_ERROR (Status)) {
602 //
603 // If an error occurs allocating the pages for the current memory type, then
604 // free all the pages allocates for the previous memory types and return. This
605 // operation with be retied when/if more memory is added to the system
606 //
607 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
608 //
609 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
610 //
611 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
612 if ((UINT32)Type > EfiMaxMemoryType) {
613 continue;
614 }
615
616 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
617 CoreFreePages (
618 mMemoryTypeStatistics[Type].BaseAddress,
619 gMemoryTypeInformation[FreeIndex].NumberOfPages
620 );
621 mMemoryTypeStatistics[Type].BaseAddress = 0;
622 mMemoryTypeStatistics[Type].MaximumAddress = MAX_ADDRESS;
623 }
624 }
625 return;
626 }
627
628 //
629 // Compute the address at the top of the current statistics
630 //
631 mMemoryTypeStatistics[Type].MaximumAddress =
632 mMemoryTypeStatistics[Type].BaseAddress +
633 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
634
635 //
636 // If the current base address is the lowest address so far, then update the default
637 // maximum address
638 //
639 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
640 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
641 }
642 }
643 }
644
645 //
646 // There was enough system memory for all the the memory types were allocated. So,
647 // those memory areas can be freed for future allocations, and all future memory
648 // allocations can occur within their respective bins
649 //
650 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
651 //
652 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
653 //
654 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
655 if ((UINT32)Type > EfiMaxMemoryType) {
656 continue;
657 }
658 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
659 CoreFreePages (
660 mMemoryTypeStatistics[Type].BaseAddress,
661 gMemoryTypeInformation[Index].NumberOfPages
662 );
663 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
664 gMemoryTypeInformation[Index].NumberOfPages = 0;
665 }
666 }
667
668 //
669 // If the number of pages reserved for a memory type is 0, then all allocations for that type
670 // should be in the default range.
671 //
672 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
673 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
674 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
675 mMemoryTypeStatistics[Type].InformationIndex = Index;
676 }
677 }
678 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
679 if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ADDRESS) {
680 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
681 }
682 }
683
684 mMemoryTypeInformationInitialized = TRUE;
685 }
686
687
688 /**
689 Internal function. Converts a memory range to the specified type or attributes.
690 The range must exist in the memory map. Either ChangingType or
691 ChangingAttributes must be set, but not both.
692
693 @param Start The first address of the range Must be page
694 aligned
695 @param NumberOfPages The number of pages to convert
696 @param ChangingType Boolean indicating that type value should be changed
697 @param NewType The new type for the memory range
698 @param ChangingAttributes Boolean indicating that attributes value should be changed
699 @param NewAttributes The new attributes 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 EFI_STATUS
709 CoreConvertPagesEx (
710 IN UINT64 Start,
711 IN UINT64 NumberOfPages,
712 IN BOOLEAN ChangingType,
713 IN EFI_MEMORY_TYPE NewType,
714 IN BOOLEAN ChangingAttributes,
715 IN UINT64 NewAttributes
716 )
717 {
718
719 UINT64 NumberOfBytes;
720 UINT64 End;
721 UINT64 RangeEnd;
722 UINT64 Attribute;
723 EFI_MEMORY_TYPE MemType;
724 LIST_ENTRY *Link;
725 MEMORY_MAP *Entry;
726
727 Entry = NULL;
728 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
729 End = Start + NumberOfBytes - 1;
730
731 ASSERT (NumberOfPages);
732 ASSERT ((Start & EFI_PAGE_MASK) == 0);
733 ASSERT (End > Start) ;
734 ASSERT_LOCKED (&gMemoryLock);
735 ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );
736
737 if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
738 return EFI_INVALID_PARAMETER;
739 }
740
741 //
742 // Convert the entire range
743 //
744
745 while (Start < End) {
746
747 //
748 // Find the entry that the covers the range
749 //
750 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
751 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
752
753 if (Entry->Start <= Start && Entry->End > Start) {
754 break;
755 }
756 }
757
758 if (Link == &gMemoryMap) {
759 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
760 return EFI_NOT_FOUND;
761 }
762
763 //
764 // If we are converting the type of the range from EfiConventionalMemory to
765 // another type, we have to ensure that the entire range is covered by a
766 // single entry.
767 //
768 if (ChangingType && (NewType != EfiConventionalMemory)) {
769 if (Entry->End < End) {
770 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
771 return EFI_NOT_FOUND;
772 }
773 }
774 //
775 // Convert range to the end, or to the end of the descriptor
776 // if that's all we've got
777 //
778 RangeEnd = End;
779
780 ASSERT (Entry != NULL);
781 if (Entry->End < End) {
782 RangeEnd = Entry->End;
783 }
784
785 if (ChangingType) {
786 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
787 }
788 if (ChangingAttributes) {
789 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
790 }
791
792 if (ChangingType) {
793 //
794 // Debug code - verify conversion is allowed
795 //
796 if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
797 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
798 if (Entry->Type == EfiConventionalMemory) {
799 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
800 } else {
801 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
802 }
803 return EFI_NOT_FOUND;
804 }
805
806 //
807 // Update counters for the number of pages allocated to each memory type
808 //
809 if ((UINT32)Entry->Type < EfiMaxMemoryType) {
810 if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
811 (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
812 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
813 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
814 } else {
815 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
816 }
817 }
818 }
819
820 if ((UINT32)NewType < EfiMaxMemoryType) {
821 if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
822 (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
823 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
824 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
825 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
826 }
827 }
828 }
829 }
830
831 //
832 // Pull range out of descriptor
833 //
834 if (Entry->Start == Start) {
835
836 //
837 // Clip start
838 //
839 Entry->Start = RangeEnd + 1;
840
841 } else if (Entry->End == RangeEnd) {
842
843 //
844 // Clip end
845 //
846 Entry->End = Start - 1;
847
848 } else {
849
850 //
851 // Pull it out of the center, clip current
852 //
853
854 //
855 // Add a new one
856 //
857 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
858 mMapStack[mMapDepth].FromPages = FALSE;
859 mMapStack[mMapDepth].Type = Entry->Type;
860 mMapStack[mMapDepth].Start = RangeEnd+1;
861 mMapStack[mMapDepth].End = Entry->End;
862
863 //
864 // Inherit Attribute from the Memory Descriptor that is being clipped
865 //
866 mMapStack[mMapDepth].Attribute = Entry->Attribute;
867
868 Entry->End = Start - 1;
869 ASSERT (Entry->Start < Entry->End);
870
871 Entry = &mMapStack[mMapDepth];
872 InsertTailList (&gMemoryMap, &Entry->Link);
873
874 mMapDepth += 1;
875 ASSERT (mMapDepth < MAX_MAP_DEPTH);
876 }
877
878 //
879 // The new range inherits the same Attribute as the Entry
880 // it is being cut out of unless attributes are being changed
881 //
882 if (ChangingType) {
883 Attribute = Entry->Attribute;
884 MemType = NewType;
885 } else {
886 Attribute = NewAttributes;
887 MemType = Entry->Type;
888 }
889
890 //
891 // If the descriptor is empty, then remove it from the map
892 //
893 if (Entry->Start == Entry->End + 1) {
894 RemoveMemoryMapEntry (Entry);
895 Entry = NULL;
896 }
897
898 //
899 // Add our new range in
900 //
901 CoreAddRange (MemType, Start, RangeEnd, Attribute);
902 if (ChangingType && (MemType == EfiConventionalMemory)) {
903 if (Start == 0) {
904 //
905 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
906 // macro will ASSERT() if address is 0. Instead, CoreAddRange()
907 // guarantees that the page starting at address 0 is always filled
908 // with zeros.
909 //
910 if (RangeEnd > EFI_PAGE_SIZE) {
911 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
912 }
913 } else {
914 //
915 // If Heap Guard is enabled, the page at the top and/or bottom of
916 // this memory block to free might be inaccessible. Skipping them
917 // to avoid page fault exception.
918 //
919 UINT64 StartToClear;
920 UINT64 EndToClear;
921
922 StartToClear = Start;
923 EndToClear = RangeEnd + 1;
924 if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) {
925 if (IsGuardPage(StartToClear)) {
926 StartToClear += EFI_PAGE_SIZE;
927 }
928 if (IsGuardPage (EndToClear - 1)) {
929 EndToClear -= EFI_PAGE_SIZE;
930 }
931 }
932
933 if (EndToClear > StartToClear) {
934 DEBUG_CLEAR_MEMORY(
935 (VOID *)(UINTN)StartToClear,
936 (UINTN)(EndToClear - StartToClear)
937 );
938 }
939 }
940 }
941
942 //
943 // Move any map descriptor stack to general pool
944 //
945 CoreFreeMemoryMapStack ();
946
947 //
948 // Bump the starting address, and convert the next range
949 //
950 Start = RangeEnd + 1;
951 }
952
953 //
954 // Converted the whole range, done
955 //
956
957 return EFI_SUCCESS;
958 }
959
960
961 /**
962 Internal function. Converts a memory range to the specified type.
963 The range must exist in the memory map.
964
965 @param Start The first address of the range Must be page
966 aligned
967 @param NumberOfPages The number of pages to convert
968 @param NewType The new type for the memory range
969
970 @retval EFI_INVALID_PARAMETER Invalid parameter
971 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
972 range or convertion not allowed.
973 @retval EFI_SUCCESS Successfully converts the memory range to the
974 specified type.
975
976 **/
977 EFI_STATUS
978 CoreConvertPages (
979 IN UINT64 Start,
980 IN UINT64 NumberOfPages,
981 IN EFI_MEMORY_TYPE NewType
982 )
983 {
984 return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
985 }
986
987
988 /**
989 Internal function. Converts a memory range to use new attributes.
990
991 @param Start The first address of the range Must be page
992 aligned
993 @param NumberOfPages The number of pages to convert
994 @param NewAttributes The new attributes value for the range.
995
996 **/
997 VOID
998 CoreUpdateMemoryAttributes (
999 IN EFI_PHYSICAL_ADDRESS Start,
1000 IN UINT64 NumberOfPages,
1001 IN UINT64 NewAttributes
1002 )
1003 {
1004 CoreAcquireMemoryLock ();
1005
1006 //
1007 // Update the attributes to the new value
1008 //
1009 CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
1010
1011 CoreReleaseMemoryLock ();
1012 }
1013
1014
1015 /**
1016 Internal function. Finds a consecutive free page range below
1017 the requested address.
1018
1019 @param MaxAddress The address that the range must be below
1020 @param MinAddress The address that the range must be above
1021 @param NumberOfPages Number of pages needed
1022 @param NewType The type of memory the range is going to be
1023 turned into
1024 @param Alignment Bits to align with
1025 @param NeedGuard Flag to indicate Guard page is needed or not
1026
1027 @return The base address of the range, or 0 if the range was not found
1028
1029 **/
1030 UINT64
1031 CoreFindFreePagesI (
1032 IN UINT64 MaxAddress,
1033 IN UINT64 MinAddress,
1034 IN UINT64 NumberOfPages,
1035 IN EFI_MEMORY_TYPE NewType,
1036 IN UINTN Alignment,
1037 IN BOOLEAN NeedGuard
1038 )
1039 {
1040 UINT64 NumberOfBytes;
1041 UINT64 Target;
1042 UINT64 DescStart;
1043 UINT64 DescEnd;
1044 UINT64 DescNumberOfBytes;
1045 LIST_ENTRY *Link;
1046 MEMORY_MAP *Entry;
1047
1048 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
1049 return 0;
1050 }
1051
1052 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
1053
1054 //
1055 // If MaxAddress is not aligned to the end of a page
1056 //
1057
1058 //
1059 // Change MaxAddress to be 1 page lower
1060 //
1061 MaxAddress -= (EFI_PAGE_MASK + 1);
1062
1063 //
1064 // Set MaxAddress to a page boundary
1065 //
1066 MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
1067
1068 //
1069 // Set MaxAddress to end of the page
1070 //
1071 MaxAddress |= EFI_PAGE_MASK;
1072 }
1073
1074 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1075 Target = 0;
1076
1077 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1078 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1079
1080 //
1081 // If it's not a free entry, don't bother with it
1082 //
1083 if (Entry->Type != EfiConventionalMemory) {
1084 continue;
1085 }
1086
1087 DescStart = Entry->Start;
1088 DescEnd = Entry->End;
1089
1090 //
1091 // If desc is past max allowed address or below min allowed address, skip it
1092 //
1093 if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
1094 continue;
1095 }
1096
1097 //
1098 // If desc ends past max allowed address, clip the end
1099 //
1100 if (DescEnd >= MaxAddress) {
1101 DescEnd = MaxAddress;
1102 }
1103
1104 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
1105
1106 // Skip if DescEnd is less than DescStart after alignment clipping
1107 if (DescEnd < DescStart) {
1108 continue;
1109 }
1110
1111 //
1112 // Compute the number of bytes we can used from this
1113 // descriptor, and see it's enough to satisfy the request
1114 //
1115 DescNumberOfBytes = DescEnd - DescStart + 1;
1116
1117 if (DescNumberOfBytes >= NumberOfBytes) {
1118 //
1119 // If the start of the allocated range is below the min address allowed, skip it
1120 //
1121 if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
1122 continue;
1123 }
1124
1125 //
1126 // If this is the best match so far remember it
1127 //
1128 if (DescEnd > Target) {
1129 if (NeedGuard) {
1130 DescEnd = AdjustMemoryS (
1131 DescEnd + 1 - DescNumberOfBytes,
1132 DescNumberOfBytes,
1133 NumberOfBytes
1134 );
1135 if (DescEnd == 0) {
1136 continue;
1137 }
1138 }
1139
1140 Target = DescEnd;
1141 }
1142 }
1143 }
1144
1145 //
1146 // If this is a grow down, adjust target to be the allocation base
1147 //
1148 Target -= NumberOfBytes - 1;
1149
1150 //
1151 // If we didn't find a match, return 0
1152 //
1153 if ((Target & EFI_PAGE_MASK) != 0) {
1154 return 0;
1155 }
1156
1157 return Target;
1158 }
1159
1160
1161 /**
1162 Internal function. Finds a consecutive free page range below
1163 the requested address
1164
1165 @param MaxAddress The address that the range must be below
1166 @param NoPages Number of pages needed
1167 @param NewType The type of memory the range is going to be
1168 turned into
1169 @param Alignment Bits to align with
1170 @param NeedGuard Flag to indicate Guard page is needed or not
1171
1172 @return The base address of the range, or 0 if the range was not found.
1173
1174 **/
1175 UINT64
1176 FindFreePages (
1177 IN UINT64 MaxAddress,
1178 IN UINT64 NoPages,
1179 IN EFI_MEMORY_TYPE NewType,
1180 IN UINTN Alignment,
1181 IN BOOLEAN NeedGuard
1182 )
1183 {
1184 UINT64 Start;
1185
1186 //
1187 // Attempt to find free pages in the preferred bin based on the requested memory type
1188 //
1189 if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
1190 Start = CoreFindFreePagesI (
1191 mMemoryTypeStatistics[NewType].MaximumAddress,
1192 mMemoryTypeStatistics[NewType].BaseAddress,
1193 NoPages,
1194 NewType,
1195 Alignment,
1196 NeedGuard
1197 );
1198 if (Start != 0) {
1199 return Start;
1200 }
1201 }
1202
1203 //
1204 // Attempt to find free pages in the default allocation bin
1205 //
1206 if (MaxAddress >= mDefaultMaximumAddress) {
1207 Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,
1208 Alignment, NeedGuard);
1209 if (Start != 0) {
1210 if (Start < mDefaultBaseAddress) {
1211 mDefaultBaseAddress = Start;
1212 }
1213 return Start;
1214 }
1215 }
1216
1217 //
1218 // The allocation did not succeed in any of the prefered bins even after
1219 // promoting resources. Attempt to find free pages anywhere is the requested
1220 // address range. If this allocation fails, then there are not enough
1221 // resources anywhere to satisfy the request.
1222 //
1223 Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,
1224 NeedGuard);
1225 if (Start != 0) {
1226 return Start;
1227 }
1228
1229 //
1230 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1231 //
1232 if (!PromoteMemoryResource ()) {
1233 return 0;
1234 }
1235
1236 //
1237 // If any memory resources were promoted, then re-attempt the allocation
1238 //
1239 return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
1240 }
1241
1242
1243 /**
1244 Allocates pages from the memory map.
1245
1246 @param Type The type of allocation to perform
1247 @param MemoryType The type of memory to turn the allocated pages
1248 into
1249 @param NumberOfPages The number of pages to allocate
1250 @param Memory A pointer to receive the base allocated memory
1251 address
1252 @param NeedGuard Flag to indicate Guard page is needed or not
1253
1254 @return Status. On success, Memory is filled in with the base address allocated
1255 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1256 spec.
1257 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1258 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1259 @retval EFI_SUCCESS Pages successfully allocated.
1260
1261 **/
1262 EFI_STATUS
1263 EFIAPI
1264 CoreInternalAllocatePages (
1265 IN EFI_ALLOCATE_TYPE Type,
1266 IN EFI_MEMORY_TYPE MemoryType,
1267 IN UINTN NumberOfPages,
1268 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
1269 IN BOOLEAN NeedGuard
1270 )
1271 {
1272 EFI_STATUS Status;
1273 UINT64 Start;
1274 UINT64 NumberOfBytes;
1275 UINT64 End;
1276 UINT64 MaxAddress;
1277 UINTN Alignment;
1278
1279 if ((UINT32)Type >= MaxAllocateType) {
1280 return EFI_INVALID_PARAMETER;
1281 }
1282
1283 if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
1284 (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1285 return EFI_INVALID_PARAMETER;
1286 }
1287
1288 if (Memory == NULL) {
1289 return EFI_INVALID_PARAMETER;
1290 }
1291
1292 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1293
1294 if (MemoryType == EfiACPIReclaimMemory ||
1295 MemoryType == EfiACPIMemoryNVS ||
1296 MemoryType == EfiRuntimeServicesCode ||
1297 MemoryType == EfiRuntimeServicesData) {
1298
1299 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1300 }
1301
1302 if (Type == AllocateAddress) {
1303 if ((*Memory & (Alignment - 1)) != 0) {
1304 return EFI_NOT_FOUND;
1305 }
1306 }
1307
1308 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1309 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1310
1311 //
1312 // If this is for below a particular address, then
1313 //
1314 Start = *Memory;
1315
1316 //
1317 // The max address is the max natively addressable address for the processor
1318 //
1319 MaxAddress = MAX_ADDRESS;
1320
1321 //
1322 // Check for Type AllocateAddress,
1323 // if NumberOfPages is 0 or
1324 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ADDRESS or
1325 // if (Start + NumberOfBytes) rolls over 0 or
1326 // if Start is above MAX_ADDRESS or
1327 // if End is above MAX_ADDRESS,
1328 // return EFI_NOT_FOUND.
1329 //
1330 if (Type == AllocateAddress) {
1331 if ((NumberOfPages == 0) ||
1332 (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
1333 return EFI_NOT_FOUND;
1334 }
1335 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1336 End = Start + NumberOfBytes - 1;
1337
1338 if ((Start >= End) ||
1339 (Start > MaxAddress) ||
1340 (End > MaxAddress)) {
1341 return EFI_NOT_FOUND;
1342 }
1343 }
1344
1345 if (Type == AllocateMaxAddress) {
1346 MaxAddress = Start;
1347 }
1348
1349 CoreAcquireMemoryLock ();
1350
1351 //
1352 // If not a specific address, then find an address to allocate
1353 //
1354 if (Type != AllocateAddress) {
1355 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
1356 NeedGuard);
1357 if (Start == 0) {
1358 Status = EFI_OUT_OF_RESOURCES;
1359 goto Done;
1360 }
1361 }
1362
1363 //
1364 // Convert pages from FreeMemory to the requested type
1365 //
1366 if (NeedGuard) {
1367 Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
1368 } else {
1369 Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
1370 }
1371
1372 Done:
1373 CoreReleaseMemoryLock ();
1374
1375 if (!EFI_ERROR (Status)) {
1376 if (NeedGuard) {
1377 SetGuardForMemory (Start, NumberOfPages);
1378 }
1379 *Memory = Start;
1380 }
1381
1382 return Status;
1383 }
1384
1385 /**
1386 Allocates pages from the memory map.
1387
1388 @param Type The type of allocation to perform
1389 @param MemoryType The type of memory to turn the allocated pages
1390 into
1391 @param NumberOfPages The number of pages to allocate
1392 @param Memory A pointer to receive the base allocated memory
1393 address
1394
1395 @return Status. On success, Memory is filled in with the base address allocated
1396 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1397 spec.
1398 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1399 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1400 @retval EFI_SUCCESS Pages successfully allocated.
1401
1402 **/
1403 EFI_STATUS
1404 EFIAPI
1405 CoreAllocatePages (
1406 IN EFI_ALLOCATE_TYPE Type,
1407 IN EFI_MEMORY_TYPE MemoryType,
1408 IN UINTN NumberOfPages,
1409 OUT EFI_PHYSICAL_ADDRESS *Memory
1410 )
1411 {
1412 EFI_STATUS Status;
1413 BOOLEAN NeedGuard;
1414
1415 NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
1416 Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
1417 NeedGuard);
1418 if (!EFI_ERROR (Status)) {
1419 CoreUpdateProfile (
1420 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1421 MemoryProfileActionAllocatePages,
1422 MemoryType,
1423 EFI_PAGES_TO_SIZE (NumberOfPages),
1424 (VOID *) (UINTN) *Memory,
1425 NULL
1426 );
1427 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1428 ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
1429 EFI_PAGES_TO_SIZE (NumberOfPages));
1430 }
1431 return Status;
1432 }
1433
1434 /**
1435 Frees previous allocated pages.
1436
1437 @param Memory Base address of memory being freed
1438 @param NumberOfPages The number of pages to free
1439 @param MemoryType Pointer to memory type
1440
1441 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1442 @retval EFI_INVALID_PARAMETER Address not aligned
1443 @return EFI_SUCCESS -Pages successfully freed.
1444
1445 **/
1446 EFI_STATUS
1447 EFIAPI
1448 CoreInternalFreePages (
1449 IN EFI_PHYSICAL_ADDRESS Memory,
1450 IN UINTN NumberOfPages,
1451 OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
1452 )
1453 {
1454 EFI_STATUS Status;
1455 LIST_ENTRY *Link;
1456 MEMORY_MAP *Entry;
1457 UINTN Alignment;
1458 BOOLEAN IsGuarded;
1459
1460 //
1461 // Free the range
1462 //
1463 CoreAcquireMemoryLock ();
1464
1465 //
1466 // Find the entry that the covers the range
1467 //
1468 IsGuarded = FALSE;
1469 Entry = NULL;
1470 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1471 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1472 if (Entry->Start <= Memory && Entry->End > Memory) {
1473 break;
1474 }
1475 }
1476 if (Link == &gMemoryMap) {
1477 Status = EFI_NOT_FOUND;
1478 goto Done;
1479 }
1480
1481 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1482
1483 ASSERT (Entry != NULL);
1484 if (Entry->Type == EfiACPIReclaimMemory ||
1485 Entry->Type == EfiACPIMemoryNVS ||
1486 Entry->Type == EfiRuntimeServicesCode ||
1487 Entry->Type == EfiRuntimeServicesData) {
1488
1489 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1490
1491 }
1492
1493 if ((Memory & (Alignment - 1)) != 0) {
1494 Status = EFI_INVALID_PARAMETER;
1495 goto Done;
1496 }
1497
1498 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1499 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1500
1501 if (MemoryType != NULL) {
1502 *MemoryType = Entry->Type;
1503 }
1504
1505 IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
1506 IsMemoryGuarded (Memory);
1507 if (IsGuarded) {
1508 Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
1509 EfiConventionalMemory);
1510 } else {
1511 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1512 }
1513
1514 Done:
1515 CoreReleaseMemoryLock ();
1516 if (IsGuarded) {
1517 UnsetGuardForMemory(Memory, NumberOfPages);
1518 }
1519 return Status;
1520 }
1521
1522 /**
1523 Frees previous allocated pages.
1524
1525 @param Memory Base address of memory being freed
1526 @param NumberOfPages The number of pages to free
1527
1528 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1529 @retval EFI_INVALID_PARAMETER Address not aligned
1530 @return EFI_SUCCESS -Pages successfully freed.
1531
1532 **/
1533 EFI_STATUS
1534 EFIAPI
1535 CoreFreePages (
1536 IN EFI_PHYSICAL_ADDRESS Memory,
1537 IN UINTN NumberOfPages
1538 )
1539 {
1540 EFI_STATUS Status;
1541 EFI_MEMORY_TYPE MemoryType;
1542
1543 Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
1544 if (!EFI_ERROR (Status)) {
1545 CoreUpdateProfile (
1546 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1547 MemoryProfileActionFreePages,
1548 MemoryType,
1549 EFI_PAGES_TO_SIZE (NumberOfPages),
1550 (VOID *) (UINTN) Memory,
1551 NULL
1552 );
1553 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1554 ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory,
1555 EFI_PAGES_TO_SIZE (NumberOfPages));
1556 }
1557 return Status;
1558 }
1559
1560 /**
1561 This function checks to see if the last memory map descriptor in a memory map
1562 can be merged with any of the other memory map descriptors in a memorymap.
1563 Memory descriptors may be merged if they are adjacent and have the same type
1564 and attributes.
1565
1566 @param MemoryMap A pointer to the start of the memory map.
1567 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1568 @param DescriptorSize The size, in bytes, of an individual
1569 EFI_MEMORY_DESCRIPTOR.
1570
1571 @return A pointer to the next available descriptor in MemoryMap
1572
1573 **/
1574 EFI_MEMORY_DESCRIPTOR *
1575 MergeMemoryMapDescriptor (
1576 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
1577 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
1578 IN UINTN DescriptorSize
1579 )
1580 {
1581 //
1582 // Traverse the array of descriptors in MemoryMap
1583 //
1584 for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1585 //
1586 // Check to see if the Type fields are identical.
1587 //
1588 if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1589 continue;
1590 }
1591
1592 //
1593 // Check to see if the Attribute fields are identical.
1594 //
1595 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1596 continue;
1597 }
1598
1599 //
1600 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1601 //
1602 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1603 //
1604 // Merge MemoryMapDescriptor into MemoryMap
1605 //
1606 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1607
1608 //
1609 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1610 //
1611 return MemoryMapDescriptor;
1612 }
1613
1614 //
1615 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1616 //
1617 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1618 //
1619 // Merge MemoryMapDescriptor into MemoryMap
1620 //
1621 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
1622 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
1623 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1624
1625 //
1626 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1627 //
1628 return MemoryMapDescriptor;
1629 }
1630 }
1631
1632 //
1633 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1634 //
1635 // Return the slot immediately after MemoryMapDescriptor as the next available
1636 // slot in the MemoryMap array
1637 //
1638 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1639 }
1640
1641 /**
1642 This function returns a copy of the current memory map. The map is an array of
1643 memory descriptors, each of which describes a contiguous block of memory.
1644
1645 @param MemoryMapSize A pointer to the size, in bytes, of the
1646 MemoryMap buffer. On input, this is the size of
1647 the buffer allocated by the caller. On output,
1648 it is the size of the buffer returned by the
1649 firmware if the buffer was large enough, or the
1650 size of the buffer needed to contain the map if
1651 the buffer was too small.
1652 @param MemoryMap A pointer to the buffer in which firmware places
1653 the current memory map.
1654 @param MapKey A pointer to the location in which firmware
1655 returns the key for the current memory map.
1656 @param DescriptorSize A pointer to the location in which firmware
1657 returns the size, in bytes, of an individual
1658 EFI_MEMORY_DESCRIPTOR.
1659 @param DescriptorVersion A pointer to the location in which firmware
1660 returns the version number associated with the
1661 EFI_MEMORY_DESCRIPTOR.
1662
1663 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1664 buffer.
1665 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1666 buffer size needed to hold the memory map is
1667 returned in MemoryMapSize.
1668 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1669
1670 **/
1671 EFI_STATUS
1672 EFIAPI
1673 CoreGetMemoryMap (
1674 IN OUT UINTN *MemoryMapSize,
1675 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1676 OUT UINTN *MapKey,
1677 OUT UINTN *DescriptorSize,
1678 OUT UINT32 *DescriptorVersion
1679 )
1680 {
1681 EFI_STATUS Status;
1682 UINTN Size;
1683 UINTN BufferSize;
1684 UINTN NumberOfEntries;
1685 LIST_ENTRY *Link;
1686 MEMORY_MAP *Entry;
1687 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1688 EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
1689 EFI_MEMORY_TYPE Type;
1690 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1691 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
1692
1693 //
1694 // Make sure the parameters are valid
1695 //
1696 if (MemoryMapSize == NULL) {
1697 return EFI_INVALID_PARAMETER;
1698 }
1699
1700 CoreAcquireGcdMemoryLock ();
1701
1702 //
1703 // Count the number of Reserved and runtime MMIO entries
1704 // And, count the number of Persistent entries.
1705 //
1706 NumberOfEntries = 0;
1707 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1708 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1709 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
1710 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1711 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1712 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1713 NumberOfEntries ++;
1714 }
1715 }
1716
1717 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1718
1719 //
1720 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1721 // prevent people from having pointer math bugs in their code.
1722 // now you have to use *DescriptorSize to make things work.
1723 //
1724 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1725
1726 if (DescriptorSize != NULL) {
1727 *DescriptorSize = Size;
1728 }
1729
1730 if (DescriptorVersion != NULL) {
1731 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1732 }
1733
1734 CoreAcquireMemoryLock ();
1735
1736 //
1737 // Compute the buffer size needed to fit the entire map
1738 //
1739 BufferSize = Size * NumberOfEntries;
1740 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1741 BufferSize += Size;
1742 }
1743
1744 if (*MemoryMapSize < BufferSize) {
1745 Status = EFI_BUFFER_TOO_SMALL;
1746 goto Done;
1747 }
1748
1749 if (MemoryMap == NULL) {
1750 Status = EFI_INVALID_PARAMETER;
1751 goto Done;
1752 }
1753
1754 //
1755 // Build the map
1756 //
1757 ZeroMem (MemoryMap, BufferSize);
1758 MemoryMapStart = MemoryMap;
1759 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1760 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1761 ASSERT (Entry->VirtualStart == 0);
1762
1763 //
1764 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1765 //
1766 MemoryMap->Type = Entry->Type;
1767 MemoryMap->PhysicalStart = Entry->Start;
1768 MemoryMap->VirtualStart = Entry->VirtualStart;
1769 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1770 //
1771 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1772 // memory type bin and needs to be converted to the same memory type as the rest of the
1773 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1774 // improves the chances for a successful S4 resume in the presence of minor page allocation
1775 // differences across reboots.
1776 //
1777 if (MemoryMap->Type == EfiConventionalMemory) {
1778 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1779 if (mMemoryTypeStatistics[Type].Special &&
1780 mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
1781 Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
1782 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
1783 MemoryMap->Type = Type;
1784 }
1785 }
1786 }
1787 MemoryMap->Attribute = Entry->Attribute;
1788 if (MemoryMap->Type < EfiMaxMemoryType) {
1789 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1790 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1791 }
1792 }
1793
1794 //
1795 // Check to see if the new Memory Map Descriptor can be merged with an
1796 // existing descriptor if they are adjacent and have the same attributes
1797 //
1798 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1799 }
1800
1801
1802 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1803 GcdMapEntry = NULL;
1804 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1805 if (Link != &mGcdMemorySpaceMap) {
1806 //
1807 // Merge adjacent same type and attribute GCD memory range
1808 //
1809 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1810
1811 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1812 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1813 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1814 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
1815 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
1816 continue;
1817 }
1818 }
1819
1820 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1821 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1822 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1823 //
1824 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1825 // it will be recorded as page PhysicalStart and NumberOfPages.
1826 //
1827 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1828 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1829
1830 //
1831 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1832 //
1833 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1834 MemoryMap->VirtualStart = 0;
1835 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1836 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1837 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1838 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1839
1840 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1841 MemoryMap->Type = EfiReservedMemoryType;
1842 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1843 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1844 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1845 } else {
1846 MemoryMap->Type = EfiMemoryMappedIO;
1847 }
1848 }
1849
1850 //
1851 // Check to see if the new Memory Map Descriptor can be merged with an
1852 // existing descriptor if they are adjacent and have the same attributes
1853 //
1854 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1855 }
1856
1857 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
1858 //
1859 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1860 // it will be recorded as page PhysicalStart and NumberOfPages.
1861 //
1862 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1863 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1864
1865 //
1866 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1867 //
1868 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1869 MemoryMap->VirtualStart = 0;
1870 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1871 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1872 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1873 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1874 MemoryMap->Type = EfiPersistentMemory;
1875
1876 //
1877 // Check to see if the new Memory Map Descriptor can be merged with an
1878 // existing descriptor if they are adjacent and have the same attributes
1879 //
1880 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1881 }
1882 if (Link == &mGcdMemorySpaceMap) {
1883 //
1884 // break loop when arrive at head.
1885 //
1886 break;
1887 }
1888 if (GcdMapEntry != NULL) {
1889 //
1890 // Copy new GCD map entry for the following GCD range merge
1891 //
1892 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1893 }
1894 }
1895
1896 //
1897 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1898 //
1899 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1900
1901 //
1902 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1903 // set attributes and change memory paging attribute accordingly.
1904 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1905 // value from Capabilities in GCD memory map. This might cause
1906 // boot problems. Clearing all paging related capabilities can
1907 // workaround it. Following code is supposed to be removed once
1908 // the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in
1909 // UEFI spec and adopted by both EDK-II Core and all supported
1910 // OSs.
1911 //
1912 MemoryMapEnd = MemoryMap;
1913 MemoryMap = MemoryMapStart;
1914 while (MemoryMap < MemoryMapEnd) {
1915 MemoryMap->Attribute &= ~(UINT64)(EFI_MEMORY_RP | EFI_MEMORY_RO |
1916 EFI_MEMORY_XP);
1917 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
1918 }
1919 MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
1920 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
1921
1922 Status = EFI_SUCCESS;
1923
1924 Done:
1925 //
1926 // Update the map key finally
1927 //
1928 if (MapKey != NULL) {
1929 *MapKey = mMemoryMapKey;
1930 }
1931
1932 CoreReleaseMemoryLock ();
1933
1934 CoreReleaseGcdMemoryLock ();
1935
1936 *MemoryMapSize = BufferSize;
1937
1938 DEBUG_CODE (
1939 if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) {
1940 DumpGuardedMemoryBitmap ();
1941 }
1942 );
1943
1944 return Status;
1945 }
1946
1947
1948 /**
1949 Internal function. Used by the pool functions to allocate pages
1950 to back pool allocation requests.
1951
1952 @param PoolType The type of memory for the new pool pages
1953 @param NumberOfPages No of pages to allocate
1954 @param Alignment Bits to align.
1955 @param NeedGuard Flag to indicate Guard page is needed or not
1956
1957 @return The allocated memory, or NULL
1958
1959 **/
1960 VOID *
1961 CoreAllocatePoolPages (
1962 IN EFI_MEMORY_TYPE PoolType,
1963 IN UINTN NumberOfPages,
1964 IN UINTN Alignment,
1965 IN BOOLEAN NeedGuard
1966 )
1967 {
1968 UINT64 Start;
1969
1970 //
1971 // Find the pages to convert
1972 //
1973 Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment,
1974 NeedGuard);
1975
1976 //
1977 // Convert it to boot services data
1978 //
1979 if (Start == 0) {
1980 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1981 } else {
1982 if (NeedGuard) {
1983 CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
1984 } else {
1985 CoreConvertPages (Start, NumberOfPages, PoolType);
1986 }
1987 }
1988
1989 return (VOID *)(UINTN) Start;
1990 }
1991
1992
1993 /**
1994 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1995
1996 @param Memory The base address to free
1997 @param NumberOfPages The number of pages to free
1998
1999 **/
2000 VOID
2001 CoreFreePoolPages (
2002 IN EFI_PHYSICAL_ADDRESS Memory,
2003 IN UINTN NumberOfPages
2004 )
2005 {
2006 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
2007 }
2008
2009
2010
2011 /**
2012 Make sure the memory map is following all the construction rules,
2013 it is the last time to check memory map error before exit boot services.
2014
2015 @param MapKey Memory map key
2016
2017 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2018 rules.
2019 @retval EFI_SUCCESS Valid memory map.
2020
2021 **/
2022 EFI_STATUS
2023 CoreTerminateMemoryMap (
2024 IN UINTN MapKey
2025 )
2026 {
2027 EFI_STATUS Status;
2028 LIST_ENTRY *Link;
2029 MEMORY_MAP *Entry;
2030
2031 Status = EFI_SUCCESS;
2032
2033 CoreAcquireMemoryLock ();
2034
2035 if (MapKey == mMemoryMapKey) {
2036
2037 //
2038 // Make sure the memory map is following all the construction rules
2039 // This is the last chance we will be able to display any messages on
2040 // the console devices.
2041 //
2042
2043 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
2044 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
2045 if (Entry->Type < EfiMaxMemoryType) {
2046 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
2047 ASSERT (Entry->Type != EfiACPIReclaimMemory);
2048 ASSERT (Entry->Type != EfiACPIMemoryNVS);
2049 if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2050 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2051 Status = EFI_INVALID_PARAMETER;
2052 goto Done;
2053 }
2054 if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2055 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2056 Status = EFI_INVALID_PARAMETER;
2057 goto Done;
2058 }
2059 }
2060 }
2061 }
2062
2063 //
2064 // The map key they gave us matches what we expect. Fall through and
2065 // return success. In an ideal world we would clear out all of
2066 // EfiBootServicesCode and EfiBootServicesData. However this function
2067 // is not the last one called by ExitBootServices(), so we have to
2068 // preserve the memory contents.
2069 //
2070 } else {
2071 Status = EFI_INVALID_PARAMETER;
2072 }
2073
2074 Done:
2075 CoreReleaseMemoryLock ();
2076
2077 return Status;
2078 }
2079
2080
2081
2082
2083
2084
2085
2086
2087