]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
1 /** @file
2 UEFI Memory page management functions.
3
4 Copyright (c) 2007 - 2018, 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 //
904 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
905 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
906 // that the page starting at address 0 is always filled with zeros.
907 //
908 if (Start == 0) {
909 if (RangeEnd > EFI_PAGE_SIZE) {
910 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
911 }
912 } else {
913 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));
914 }
915 }
916
917 //
918 // Move any map descriptor stack to general pool
919 //
920 CoreFreeMemoryMapStack ();
921
922 //
923 // Bump the starting address, and convert the next range
924 //
925 Start = RangeEnd + 1;
926 }
927
928 //
929 // Converted the whole range, done
930 //
931
932 return EFI_SUCCESS;
933 }
934
935
936 /**
937 Internal function. Converts a memory range to the specified type.
938 The range must exist in the memory map.
939
940 @param Start The first address of the range Must be page
941 aligned
942 @param NumberOfPages The number of pages to convert
943 @param NewType The new type for the memory range
944
945 @retval EFI_INVALID_PARAMETER Invalid parameter
946 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
947 range or convertion not allowed.
948 @retval EFI_SUCCESS Successfully converts the memory range to the
949 specified type.
950
951 **/
952 EFI_STATUS
953 CoreConvertPages (
954 IN UINT64 Start,
955 IN UINT64 NumberOfPages,
956 IN EFI_MEMORY_TYPE NewType
957 )
958 {
959 return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
960 }
961
962
963 /**
964 Internal function. Converts a memory range to use new attributes.
965
966 @param Start The first address of the range Must be page
967 aligned
968 @param NumberOfPages The number of pages to convert
969 @param NewAttributes The new attributes value for the range.
970
971 **/
972 VOID
973 CoreUpdateMemoryAttributes (
974 IN EFI_PHYSICAL_ADDRESS Start,
975 IN UINT64 NumberOfPages,
976 IN UINT64 NewAttributes
977 )
978 {
979 CoreAcquireMemoryLock ();
980
981 //
982 // Update the attributes to the new value
983 //
984 CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
985
986 CoreReleaseMemoryLock ();
987 }
988
989
990 /**
991 Internal function. Finds a consecutive free page range below
992 the requested address.
993
994 @param MaxAddress The address that the range must be below
995 @param MinAddress The address that the range must be above
996 @param NumberOfPages Number of pages needed
997 @param NewType The type of memory the range is going to be
998 turned into
999 @param Alignment Bits to align with
1000 @param NeedGuard Flag to indicate Guard page is needed or not
1001
1002 @return The base address of the range, or 0 if the range was not found
1003
1004 **/
1005 UINT64
1006 CoreFindFreePagesI (
1007 IN UINT64 MaxAddress,
1008 IN UINT64 MinAddress,
1009 IN UINT64 NumberOfPages,
1010 IN EFI_MEMORY_TYPE NewType,
1011 IN UINTN Alignment,
1012 IN BOOLEAN NeedGuard
1013 )
1014 {
1015 UINT64 NumberOfBytes;
1016 UINT64 Target;
1017 UINT64 DescStart;
1018 UINT64 DescEnd;
1019 UINT64 DescNumberOfBytes;
1020 LIST_ENTRY *Link;
1021 MEMORY_MAP *Entry;
1022
1023 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
1024 return 0;
1025 }
1026
1027 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
1028
1029 //
1030 // If MaxAddress is not aligned to the end of a page
1031 //
1032
1033 //
1034 // Change MaxAddress to be 1 page lower
1035 //
1036 MaxAddress -= (EFI_PAGE_MASK + 1);
1037
1038 //
1039 // Set MaxAddress to a page boundary
1040 //
1041 MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
1042
1043 //
1044 // Set MaxAddress to end of the page
1045 //
1046 MaxAddress |= EFI_PAGE_MASK;
1047 }
1048
1049 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1050 Target = 0;
1051
1052 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1053 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1054
1055 //
1056 // If it's not a free entry, don't bother with it
1057 //
1058 if (Entry->Type != EfiConventionalMemory) {
1059 continue;
1060 }
1061
1062 DescStart = Entry->Start;
1063 DescEnd = Entry->End;
1064
1065 //
1066 // If desc is past max allowed address or below min allowed address, skip it
1067 //
1068 if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
1069 continue;
1070 }
1071
1072 //
1073 // If desc ends past max allowed address, clip the end
1074 //
1075 if (DescEnd >= MaxAddress) {
1076 DescEnd = MaxAddress;
1077 }
1078
1079 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
1080
1081 // Skip if DescEnd is less than DescStart after alignment clipping
1082 if (DescEnd < DescStart) {
1083 continue;
1084 }
1085
1086 //
1087 // Compute the number of bytes we can used from this
1088 // descriptor, and see it's enough to satisfy the request
1089 //
1090 DescNumberOfBytes = DescEnd - DescStart + 1;
1091
1092 if (DescNumberOfBytes >= NumberOfBytes) {
1093 //
1094 // If the start of the allocated range is below the min address allowed, skip it
1095 //
1096 if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
1097 continue;
1098 }
1099
1100 //
1101 // If this is the best match so far remember it
1102 //
1103 if (DescEnd > Target) {
1104 if (NeedGuard) {
1105 DescEnd = AdjustMemoryS (
1106 DescEnd + 1 - DescNumberOfBytes,
1107 DescNumberOfBytes,
1108 NumberOfBytes
1109 );
1110 if (DescEnd == 0) {
1111 continue;
1112 }
1113 }
1114
1115 Target = DescEnd;
1116 }
1117 }
1118 }
1119
1120 //
1121 // If this is a grow down, adjust target to be the allocation base
1122 //
1123 Target -= NumberOfBytes - 1;
1124
1125 //
1126 // If we didn't find a match, return 0
1127 //
1128 if ((Target & EFI_PAGE_MASK) != 0) {
1129 return 0;
1130 }
1131
1132 return Target;
1133 }
1134
1135
1136 /**
1137 Internal function. Finds a consecutive free page range below
1138 the requested address
1139
1140 @param MaxAddress The address that the range must be below
1141 @param NoPages Number of pages needed
1142 @param NewType The type of memory the range is going to be
1143 turned into
1144 @param Alignment Bits to align with
1145 @param NeedGuard Flag to indicate Guard page is needed or not
1146
1147 @return The base address of the range, or 0 if the range was not found.
1148
1149 **/
1150 UINT64
1151 FindFreePages (
1152 IN UINT64 MaxAddress,
1153 IN UINT64 NoPages,
1154 IN EFI_MEMORY_TYPE NewType,
1155 IN UINTN Alignment,
1156 IN BOOLEAN NeedGuard
1157 )
1158 {
1159 UINT64 Start;
1160
1161 //
1162 // Attempt to find free pages in the preferred bin based on the requested memory type
1163 //
1164 if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
1165 Start = CoreFindFreePagesI (
1166 mMemoryTypeStatistics[NewType].MaximumAddress,
1167 mMemoryTypeStatistics[NewType].BaseAddress,
1168 NoPages,
1169 NewType,
1170 Alignment,
1171 NeedGuard
1172 );
1173 if (Start != 0) {
1174 return Start;
1175 }
1176 }
1177
1178 //
1179 // Attempt to find free pages in the default allocation bin
1180 //
1181 if (MaxAddress >= mDefaultMaximumAddress) {
1182 Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,
1183 Alignment, NeedGuard);
1184 if (Start != 0) {
1185 if (Start < mDefaultBaseAddress) {
1186 mDefaultBaseAddress = Start;
1187 }
1188 return Start;
1189 }
1190 }
1191
1192 //
1193 // The allocation did not succeed in any of the prefered bins even after
1194 // promoting resources. Attempt to find free pages anywhere is the requested
1195 // address range. If this allocation fails, then there are not enough
1196 // resources anywhere to satisfy the request.
1197 //
1198 Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,
1199 NeedGuard);
1200 if (Start != 0) {
1201 return Start;
1202 }
1203
1204 //
1205 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1206 //
1207 if (!PromoteMemoryResource ()) {
1208 return 0;
1209 }
1210
1211 //
1212 // If any memory resources were promoted, then re-attempt the allocation
1213 //
1214 return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
1215 }
1216
1217
1218 /**
1219 Allocates pages from the memory map.
1220
1221 @param Type The type of allocation to perform
1222 @param MemoryType The type of memory to turn the allocated pages
1223 into
1224 @param NumberOfPages The number of pages to allocate
1225 @param Memory A pointer to receive the base allocated memory
1226 address
1227 @param NeedGuard Flag to indicate Guard page is needed or not
1228
1229 @return Status. On success, Memory is filled in with the base address allocated
1230 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1231 spec.
1232 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1233 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1234 @retval EFI_SUCCESS Pages successfully allocated.
1235
1236 **/
1237 EFI_STATUS
1238 EFIAPI
1239 CoreInternalAllocatePages (
1240 IN EFI_ALLOCATE_TYPE Type,
1241 IN EFI_MEMORY_TYPE MemoryType,
1242 IN UINTN NumberOfPages,
1243 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
1244 IN BOOLEAN NeedGuard
1245 )
1246 {
1247 EFI_STATUS Status;
1248 UINT64 Start;
1249 UINT64 NumberOfBytes;
1250 UINT64 End;
1251 UINT64 MaxAddress;
1252 UINTN Alignment;
1253
1254 if ((UINT32)Type >= MaxAllocateType) {
1255 return EFI_INVALID_PARAMETER;
1256 }
1257
1258 if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
1259 (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1260 return EFI_INVALID_PARAMETER;
1261 }
1262
1263 if (Memory == NULL) {
1264 return EFI_INVALID_PARAMETER;
1265 }
1266
1267 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1268
1269 if (MemoryType == EfiACPIReclaimMemory ||
1270 MemoryType == EfiACPIMemoryNVS ||
1271 MemoryType == EfiRuntimeServicesCode ||
1272 MemoryType == EfiRuntimeServicesData) {
1273
1274 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1275 }
1276
1277 if (Type == AllocateAddress) {
1278 if ((*Memory & (Alignment - 1)) != 0) {
1279 return EFI_NOT_FOUND;
1280 }
1281 }
1282
1283 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1284 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1285
1286 //
1287 // If this is for below a particular address, then
1288 //
1289 Start = *Memory;
1290
1291 //
1292 // The max address is the max natively addressable address for the processor
1293 //
1294 MaxAddress = MAX_ADDRESS;
1295
1296 //
1297 // Check for Type AllocateAddress,
1298 // if NumberOfPages is 0 or
1299 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ADDRESS or
1300 // if (Start + NumberOfBytes) rolls over 0 or
1301 // if Start is above MAX_ADDRESS or
1302 // if End is above MAX_ADDRESS,
1303 // return EFI_NOT_FOUND.
1304 //
1305 if (Type == AllocateAddress) {
1306 if ((NumberOfPages == 0) ||
1307 (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
1308 return EFI_NOT_FOUND;
1309 }
1310 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1311 End = Start + NumberOfBytes - 1;
1312
1313 if ((Start >= End) ||
1314 (Start > MaxAddress) ||
1315 (End > MaxAddress)) {
1316 return EFI_NOT_FOUND;
1317 }
1318 }
1319
1320 if (Type == AllocateMaxAddress) {
1321 MaxAddress = Start;
1322 }
1323
1324 CoreAcquireMemoryLock ();
1325
1326 //
1327 // If not a specific address, then find an address to allocate
1328 //
1329 if (Type != AllocateAddress) {
1330 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
1331 NeedGuard);
1332 if (Start == 0) {
1333 Status = EFI_OUT_OF_RESOURCES;
1334 goto Done;
1335 }
1336 }
1337
1338 //
1339 // Convert pages from FreeMemory to the requested type
1340 //
1341 if (NeedGuard) {
1342 Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
1343 } else {
1344 Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
1345 }
1346
1347 Done:
1348 CoreReleaseMemoryLock ();
1349
1350 if (!EFI_ERROR (Status)) {
1351 if (NeedGuard) {
1352 SetGuardForMemory (Start, NumberOfPages);
1353 }
1354 *Memory = Start;
1355 }
1356
1357 return Status;
1358 }
1359
1360 /**
1361 Allocates pages from the memory map.
1362
1363 @param Type The type of allocation to perform
1364 @param MemoryType The type of memory to turn the allocated pages
1365 into
1366 @param NumberOfPages The number of pages to allocate
1367 @param Memory A pointer to receive the base allocated memory
1368 address
1369
1370 @return Status. On success, Memory is filled in with the base address allocated
1371 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1372 spec.
1373 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1374 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1375 @retval EFI_SUCCESS Pages successfully allocated.
1376
1377 **/
1378 EFI_STATUS
1379 EFIAPI
1380 CoreAllocatePages (
1381 IN EFI_ALLOCATE_TYPE Type,
1382 IN EFI_MEMORY_TYPE MemoryType,
1383 IN UINTN NumberOfPages,
1384 OUT EFI_PHYSICAL_ADDRESS *Memory
1385 )
1386 {
1387 EFI_STATUS Status;
1388 BOOLEAN NeedGuard;
1389
1390 NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
1391 Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
1392 NeedGuard);
1393 if (!EFI_ERROR (Status)) {
1394 CoreUpdateProfile (
1395 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1396 MemoryProfileActionAllocatePages,
1397 MemoryType,
1398 EFI_PAGES_TO_SIZE (NumberOfPages),
1399 (VOID *) (UINTN) *Memory,
1400 NULL
1401 );
1402 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1403 ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
1404 EFI_PAGES_TO_SIZE (NumberOfPages));
1405 }
1406 return Status;
1407 }
1408
1409 /**
1410 Frees previous allocated pages.
1411
1412 @param Memory Base address of memory being freed
1413 @param NumberOfPages The number of pages to free
1414 @param MemoryType Pointer to memory type
1415
1416 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1417 @retval EFI_INVALID_PARAMETER Address not aligned
1418 @return EFI_SUCCESS -Pages successfully freed.
1419
1420 **/
1421 EFI_STATUS
1422 EFIAPI
1423 CoreInternalFreePages (
1424 IN EFI_PHYSICAL_ADDRESS Memory,
1425 IN UINTN NumberOfPages,
1426 OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
1427 )
1428 {
1429 EFI_STATUS Status;
1430 LIST_ENTRY *Link;
1431 MEMORY_MAP *Entry;
1432 UINTN Alignment;
1433 BOOLEAN IsGuarded;
1434
1435 //
1436 // Free the range
1437 //
1438 CoreAcquireMemoryLock ();
1439
1440 //
1441 // Find the entry that the covers the range
1442 //
1443 IsGuarded = FALSE;
1444 Entry = NULL;
1445 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1446 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1447 if (Entry->Start <= Memory && Entry->End > Memory) {
1448 break;
1449 }
1450 }
1451 if (Link == &gMemoryMap) {
1452 Status = EFI_NOT_FOUND;
1453 goto Done;
1454 }
1455
1456 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1457
1458 ASSERT (Entry != NULL);
1459 if (Entry->Type == EfiACPIReclaimMemory ||
1460 Entry->Type == EfiACPIMemoryNVS ||
1461 Entry->Type == EfiRuntimeServicesCode ||
1462 Entry->Type == EfiRuntimeServicesData) {
1463
1464 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1465
1466 }
1467
1468 if ((Memory & (Alignment - 1)) != 0) {
1469 Status = EFI_INVALID_PARAMETER;
1470 goto Done;
1471 }
1472
1473 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1474 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1475
1476 if (MemoryType != NULL) {
1477 *MemoryType = Entry->Type;
1478 }
1479
1480 IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
1481 IsMemoryGuarded (Memory);
1482 if (IsGuarded) {
1483 Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
1484 EfiConventionalMemory);
1485 } else {
1486 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1487 }
1488
1489 Done:
1490 CoreReleaseMemoryLock ();
1491 return Status;
1492 }
1493
1494 /**
1495 Frees previous allocated pages.
1496
1497 @param Memory Base address of memory being freed
1498 @param NumberOfPages The number of pages to free
1499
1500 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1501 @retval EFI_INVALID_PARAMETER Address not aligned
1502 @return EFI_SUCCESS -Pages successfully freed.
1503
1504 **/
1505 EFI_STATUS
1506 EFIAPI
1507 CoreFreePages (
1508 IN EFI_PHYSICAL_ADDRESS Memory,
1509 IN UINTN NumberOfPages
1510 )
1511 {
1512 EFI_STATUS Status;
1513 EFI_MEMORY_TYPE MemoryType;
1514
1515 Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
1516 if (!EFI_ERROR (Status)) {
1517 CoreUpdateProfile (
1518 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1519 MemoryProfileActionFreePages,
1520 MemoryType,
1521 EFI_PAGES_TO_SIZE (NumberOfPages),
1522 (VOID *) (UINTN) Memory,
1523 NULL
1524 );
1525 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1526 ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory,
1527 EFI_PAGES_TO_SIZE (NumberOfPages));
1528 }
1529 return Status;
1530 }
1531
1532 /**
1533 This function checks to see if the last memory map descriptor in a memory map
1534 can be merged with any of the other memory map descriptors in a memorymap.
1535 Memory descriptors may be merged if they are adjacent and have the same type
1536 and attributes.
1537
1538 @param MemoryMap A pointer to the start of the memory map.
1539 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1540 @param DescriptorSize The size, in bytes, of an individual
1541 EFI_MEMORY_DESCRIPTOR.
1542
1543 @return A pointer to the next available descriptor in MemoryMap
1544
1545 **/
1546 EFI_MEMORY_DESCRIPTOR *
1547 MergeMemoryMapDescriptor (
1548 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
1549 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
1550 IN UINTN DescriptorSize
1551 )
1552 {
1553 //
1554 // Traverse the array of descriptors in MemoryMap
1555 //
1556 for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1557 //
1558 // Check to see if the Type fields are identical.
1559 //
1560 if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1561 continue;
1562 }
1563
1564 //
1565 // Check to see if the Attribute fields are identical.
1566 //
1567 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1568 continue;
1569 }
1570
1571 //
1572 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1573 //
1574 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1575 //
1576 // Merge MemoryMapDescriptor into MemoryMap
1577 //
1578 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1579
1580 //
1581 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1582 //
1583 return MemoryMapDescriptor;
1584 }
1585
1586 //
1587 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1588 //
1589 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1590 //
1591 // Merge MemoryMapDescriptor into MemoryMap
1592 //
1593 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
1594 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
1595 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1596
1597 //
1598 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1599 //
1600 return MemoryMapDescriptor;
1601 }
1602 }
1603
1604 //
1605 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1606 //
1607 // Return the slot immediately after MemoryMapDescriptor as the next available
1608 // slot in the MemoryMap array
1609 //
1610 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1611 }
1612
1613 /**
1614 This function returns a copy of the current memory map. The map is an array of
1615 memory descriptors, each of which describes a contiguous block of memory.
1616
1617 @param MemoryMapSize A pointer to the size, in bytes, of the
1618 MemoryMap buffer. On input, this is the size of
1619 the buffer allocated by the caller. On output,
1620 it is the size of the buffer returned by the
1621 firmware if the buffer was large enough, or the
1622 size of the buffer needed to contain the map if
1623 the buffer was too small.
1624 @param MemoryMap A pointer to the buffer in which firmware places
1625 the current memory map.
1626 @param MapKey A pointer to the location in which firmware
1627 returns the key for the current memory map.
1628 @param DescriptorSize A pointer to the location in which firmware
1629 returns the size, in bytes, of an individual
1630 EFI_MEMORY_DESCRIPTOR.
1631 @param DescriptorVersion A pointer to the location in which firmware
1632 returns the version number associated with the
1633 EFI_MEMORY_DESCRIPTOR.
1634
1635 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1636 buffer.
1637 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1638 buffer size needed to hold the memory map is
1639 returned in MemoryMapSize.
1640 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1641
1642 **/
1643 EFI_STATUS
1644 EFIAPI
1645 CoreGetMemoryMap (
1646 IN OUT UINTN *MemoryMapSize,
1647 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1648 OUT UINTN *MapKey,
1649 OUT UINTN *DescriptorSize,
1650 OUT UINT32 *DescriptorVersion
1651 )
1652 {
1653 EFI_STATUS Status;
1654 UINTN Size;
1655 UINTN BufferSize;
1656 UINTN NumberOfEntries;
1657 LIST_ENTRY *Link;
1658 MEMORY_MAP *Entry;
1659 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1660 EFI_GCD_MAP_ENTRY MergeGcdMapEntry;
1661 EFI_MEMORY_TYPE Type;
1662 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1663 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
1664
1665 //
1666 // Make sure the parameters are valid
1667 //
1668 if (MemoryMapSize == NULL) {
1669 return EFI_INVALID_PARAMETER;
1670 }
1671
1672 CoreAcquireGcdMemoryLock ();
1673
1674 //
1675 // Count the number of Reserved and runtime MMIO entries
1676 // And, count the number of Persistent entries.
1677 //
1678 NumberOfEntries = 0;
1679 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1680 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1681 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||
1682 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1683 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1684 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1685 NumberOfEntries ++;
1686 }
1687 }
1688
1689 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1690
1691 //
1692 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1693 // prevent people from having pointer math bugs in their code.
1694 // now you have to use *DescriptorSize to make things work.
1695 //
1696 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1697
1698 if (DescriptorSize != NULL) {
1699 *DescriptorSize = Size;
1700 }
1701
1702 if (DescriptorVersion != NULL) {
1703 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1704 }
1705
1706 CoreAcquireMemoryLock ();
1707
1708 //
1709 // Compute the buffer size needed to fit the entire map
1710 //
1711 BufferSize = Size * NumberOfEntries;
1712 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1713 BufferSize += Size;
1714 }
1715
1716 if (*MemoryMapSize < BufferSize) {
1717 Status = EFI_BUFFER_TOO_SMALL;
1718 goto Done;
1719 }
1720
1721 if (MemoryMap == NULL) {
1722 Status = EFI_INVALID_PARAMETER;
1723 goto Done;
1724 }
1725
1726 //
1727 // Build the map
1728 //
1729 ZeroMem (MemoryMap, BufferSize);
1730 MemoryMapStart = MemoryMap;
1731 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1732 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1733 ASSERT (Entry->VirtualStart == 0);
1734
1735 //
1736 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1737 //
1738 MemoryMap->Type = Entry->Type;
1739 MemoryMap->PhysicalStart = Entry->Start;
1740 MemoryMap->VirtualStart = Entry->VirtualStart;
1741 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1742 //
1743 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1744 // memory type bin and needs to be converted to the same memory type as the rest of the
1745 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1746 // improves the chances for a successful S4 resume in the presence of minor page allocation
1747 // differences across reboots.
1748 //
1749 if (MemoryMap->Type == EfiConventionalMemory) {
1750 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1751 if (mMemoryTypeStatistics[Type].Special &&
1752 mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
1753 Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
1754 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
1755 MemoryMap->Type = Type;
1756 }
1757 }
1758 }
1759 MemoryMap->Attribute = Entry->Attribute;
1760 if (MemoryMap->Type < EfiMaxMemoryType) {
1761 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1762 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1763 }
1764 }
1765
1766 //
1767 // Check to see if the new Memory Map Descriptor can be merged with an
1768 // existing descriptor if they are adjacent and have the same attributes
1769 //
1770 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1771 }
1772
1773
1774 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1775 GcdMapEntry = NULL;
1776 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1777 if (Link != &mGcdMemorySpaceMap) {
1778 //
1779 // Merge adjacent same type and attribute GCD memory range
1780 //
1781 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1782
1783 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1784 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1785 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1786 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
1787 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
1788 continue;
1789 }
1790 }
1791
1792 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1793 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1794 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1795 //
1796 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1797 // it will be recorded as page PhysicalStart and NumberOfPages.
1798 //
1799 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1800 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1801
1802 //
1803 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1804 //
1805 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1806 MemoryMap->VirtualStart = 0;
1807 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1808 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1809 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1810 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1811
1812 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1813 MemoryMap->Type = EfiReservedMemoryType;
1814 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1815 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1816 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1817 } else {
1818 MemoryMap->Type = EfiMemoryMappedIO;
1819 }
1820 }
1821
1822 //
1823 // Check to see if the new Memory Map Descriptor can be merged with an
1824 // existing descriptor if they are adjacent and have the same attributes
1825 //
1826 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1827 }
1828
1829 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {
1830 //
1831 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1832 // it will be recorded as page PhysicalStart and NumberOfPages.
1833 //
1834 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1835 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1836
1837 //
1838 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1839 //
1840 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1841 MemoryMap->VirtualStart = 0;
1842 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1843 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1844 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1845 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1846 MemoryMap->Type = EfiPersistentMemory;
1847
1848 //
1849 // Check to see if the new Memory Map Descriptor can be merged with an
1850 // existing descriptor if they are adjacent and have the same attributes
1851 //
1852 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1853 }
1854 if (Link == &mGcdMemorySpaceMap) {
1855 //
1856 // break loop when arrive at head.
1857 //
1858 break;
1859 }
1860 if (GcdMapEntry != NULL) {
1861 //
1862 // Copy new GCD map entry for the following GCD range merge
1863 //
1864 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1865 }
1866 }
1867
1868 //
1869 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1870 //
1871 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1872
1873 //
1874 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really
1875 // set attributes and change memory paging attribute accordingly.
1876 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by
1877 // value from Capabilities in GCD memory map. This might cause
1878 // boot problems. Clearing all paging related capabilities can
1879 // workaround it. Following code is supposed to be removed once
1880 // the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in
1881 // UEFI spec and adopted by both EDK-II Core and all supported
1882 // OSs.
1883 //
1884 MemoryMapEnd = MemoryMap;
1885 MemoryMap = MemoryMapStart;
1886 while (MemoryMap < MemoryMapEnd) {
1887 MemoryMap->Attribute &= ~(UINT64)(EFI_MEMORY_RP | EFI_MEMORY_RO |
1888 EFI_MEMORY_XP);
1889 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
1890 }
1891 MergeMemoryMap (MemoryMapStart, &BufferSize, Size);
1892 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);
1893
1894 Status = EFI_SUCCESS;
1895
1896 Done:
1897 //
1898 // Update the map key finally
1899 //
1900 if (MapKey != NULL) {
1901 *MapKey = mMemoryMapKey;
1902 }
1903
1904 CoreReleaseMemoryLock ();
1905
1906 CoreReleaseGcdMemoryLock ();
1907
1908 *MemoryMapSize = BufferSize;
1909
1910 DEBUG_CODE (
1911 if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) {
1912 DumpGuardedMemoryBitmap ();
1913 }
1914 );
1915
1916 return Status;
1917 }
1918
1919
1920 /**
1921 Internal function. Used by the pool functions to allocate pages
1922 to back pool allocation requests.
1923
1924 @param PoolType The type of memory for the new pool pages
1925 @param NumberOfPages No of pages to allocate
1926 @param Alignment Bits to align.
1927 @param NeedGuard Flag to indicate Guard page is needed or not
1928
1929 @return The allocated memory, or NULL
1930
1931 **/
1932 VOID *
1933 CoreAllocatePoolPages (
1934 IN EFI_MEMORY_TYPE PoolType,
1935 IN UINTN NumberOfPages,
1936 IN UINTN Alignment,
1937 IN BOOLEAN NeedGuard
1938 )
1939 {
1940 UINT64 Start;
1941
1942 //
1943 // Find the pages to convert
1944 //
1945 Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment,
1946 NeedGuard);
1947
1948 //
1949 // Convert it to boot services data
1950 //
1951 if (Start == 0) {
1952 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1953 } else {
1954 if (NeedGuard) {
1955 CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
1956 } else {
1957 CoreConvertPages (Start, NumberOfPages, PoolType);
1958 }
1959 }
1960
1961 return (VOID *)(UINTN) Start;
1962 }
1963
1964
1965 /**
1966 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1967
1968 @param Memory The base address to free
1969 @param NumberOfPages The number of pages to free
1970
1971 **/
1972 VOID
1973 CoreFreePoolPages (
1974 IN EFI_PHYSICAL_ADDRESS Memory,
1975 IN UINTN NumberOfPages
1976 )
1977 {
1978 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1979 }
1980
1981
1982
1983 /**
1984 Make sure the memory map is following all the construction rules,
1985 it is the last time to check memory map error before exit boot services.
1986
1987 @param MapKey Memory map key
1988
1989 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1990 rules.
1991 @retval EFI_SUCCESS Valid memory map.
1992
1993 **/
1994 EFI_STATUS
1995 CoreTerminateMemoryMap (
1996 IN UINTN MapKey
1997 )
1998 {
1999 EFI_STATUS Status;
2000 LIST_ENTRY *Link;
2001 MEMORY_MAP *Entry;
2002
2003 Status = EFI_SUCCESS;
2004
2005 CoreAcquireMemoryLock ();
2006
2007 if (MapKey == mMemoryMapKey) {
2008
2009 //
2010 // Make sure the memory map is following all the construction rules
2011 // This is the last chance we will be able to display any messages on
2012 // the console devices.
2013 //
2014
2015 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
2016 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
2017 if (Entry->Type < EfiMaxMemoryType) {
2018 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
2019 ASSERT (Entry->Type != EfiACPIReclaimMemory);
2020 ASSERT (Entry->Type != EfiACPIMemoryNVS);
2021 if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2022 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2023 Status = EFI_INVALID_PARAMETER;
2024 goto Done;
2025 }
2026 if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2027 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2028 Status = EFI_INVALID_PARAMETER;
2029 goto Done;
2030 }
2031 }
2032 }
2033 }
2034
2035 //
2036 // The map key they gave us matches what we expect. Fall through and
2037 // return success. In an ideal world we would clear out all of
2038 // EfiBootServicesCode and EfiBootServicesData. However this function
2039 // is not the last one called by ExitBootServices(), so we have to
2040 // preserve the memory contents.
2041 //
2042 } else {
2043 Status = EFI_INVALID_PARAMETER;
2044 }
2045
2046 Done:
2047 CoreReleaseMemoryLock ();
2048
2049 return Status;
2050 }
2051
2052
2053
2054
2055
2056
2057
2058
2059