]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg/Dxe/Page: take MAX_ALLOC_ADDRESS into account
[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_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
56 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
57 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
58 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
59 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
60 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
61 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
62 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
63 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
64 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
65 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
66 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
67 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
68 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
69 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory
70 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
71 };
72
73 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
74 EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_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 EFI_PHYSICAL_ADDRESS StartAddress;
408 EFI_PHYSICAL_ADDRESS EndAddress;
409 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
410
411 DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
412
413 CoreAcquireGcdMemoryLock ();
414
415 Promoted = FALSE;
416 Link = mGcdMemorySpaceMap.ForwardLink;
417 while (Link != &mGcdMemorySpaceMap) {
418
419 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
420
421 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
422 Entry->EndAddress < MAX_ALLOC_ADDRESS &&
423 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
424 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
425 //
426 // Update the GCD map
427 //
428 if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
429 Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
430 } else {
431 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
432 }
433 Entry->Capabilities |= EFI_MEMORY_TESTED;
434 Entry->ImageHandle = gDxeCoreImageHandle;
435 Entry->DeviceHandle = NULL;
436
437 //
438 // Add to allocable system memory resource
439 //
440
441 CoreAddRange (
442 EfiConventionalMemory,
443 Entry->BaseAddress,
444 Entry->EndAddress,
445 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
446 );
447 CoreFreeMemoryMapStack ();
448
449 Promoted = TRUE;
450 }
451
452 Link = Link->ForwardLink;
453 }
454
455 CoreReleaseGcdMemoryLock ();
456
457 if (!Promoted) {
458 //
459 // If freed-memory guard is enabled, we could promote pages from
460 // guarded free pages.
461 //
462 Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);
463 if (Promoted) {
464 CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor);
465 CoreAddRange (
466 EfiConventionalMemory,
467 StartAddress,
468 EndAddress,
469 Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |
470 EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
471 );
472 }
473 }
474
475 return Promoted;
476 }
477 /**
478 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
479 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
480 size of boot time and runtime code.
481
482 **/
483 VOID
484 CoreLoadingFixedAddressHook (
485 VOID
486 )
487 {
488 UINT32 RuntimeCodePageNumber;
489 UINT32 BootTimeCodePageNumber;
490 EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
491 EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
492 EFI_STATUS Status;
493
494 //
495 // Make sure these 2 areas are not initialzied.
496 //
497 if (!gLoadFixedAddressCodeMemoryReady) {
498 RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
499 BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
500 RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
501 BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
502 //
503 // Try to allocate runtime memory.
504 //
505 Status = CoreAllocatePages (
506 AllocateAddress,
507 EfiRuntimeServicesCode,
508 RuntimeCodePageNumber,
509 &RuntimeCodeBase
510 );
511 if (EFI_ERROR(Status)) {
512 //
513 // Runtime memory allocation failed
514 //
515 return;
516 }
517 //
518 // Try to allocate boot memory.
519 //
520 Status = CoreAllocatePages (
521 AllocateAddress,
522 EfiBootServicesCode,
523 BootTimeCodePageNumber,
524 &BootTimeCodeBase
525 );
526 if (EFI_ERROR(Status)) {
527 //
528 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
529 // new memory range is installed.
530 //
531 CoreFreePages (
532 RuntimeCodeBase,
533 RuntimeCodePageNumber
534 );
535 return;
536 }
537 gLoadFixedAddressCodeMemoryReady = TRUE;
538 }
539 return;
540 }
541
542 /**
543 Called to initialize the memory map and add descriptors to
544 the current descriptor list.
545 The first descriptor that is added must be general usable
546 memory as the addition allocates heap.
547
548 @param Type The type of memory to add
549 @param Start The starting address in the memory range Must be
550 page aligned
551 @param NumberOfPages The number of pages in the range
552 @param Attribute Attributes of the memory to add
553
554 @return None. The range is added to the memory map
555
556 **/
557 VOID
558 CoreAddMemoryDescriptor (
559 IN EFI_MEMORY_TYPE Type,
560 IN EFI_PHYSICAL_ADDRESS Start,
561 IN UINT64 NumberOfPages,
562 IN UINT64 Attribute
563 )
564 {
565 EFI_PHYSICAL_ADDRESS End;
566 EFI_STATUS Status;
567 UINTN Index;
568 UINTN FreeIndex;
569
570 if ((Start & EFI_PAGE_MASK) != 0) {
571 return;
572 }
573
574 if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) {
575 return;
576 }
577 CoreAcquireMemoryLock ();
578 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
579 CoreAddRange (Type, Start, End, Attribute);
580 CoreFreeMemoryMapStack ();
581 CoreReleaseMemoryLock ();
582
583 ApplyMemoryProtectionPolicy (EfiMaxMemoryType, Type, Start,
584 LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT));
585
586 //
587 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
588 //
589 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
590 CoreLoadingFixedAddressHook();
591 }
592
593 //
594 // Check to see if the statistics for the different memory types have already been established
595 //
596 if (mMemoryTypeInformationInitialized) {
597 return;
598 }
599
600
601 //
602 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
603 //
604 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
605 //
606 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
607 //
608 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
609 if ((UINT32)Type > EfiMaxMemoryType) {
610 continue;
611 }
612 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
613 //
614 // Allocate pages for the current memory type from the top of available memory
615 //
616 Status = CoreAllocatePages (
617 AllocateAnyPages,
618 Type,
619 gMemoryTypeInformation[Index].NumberOfPages,
620 &mMemoryTypeStatistics[Type].BaseAddress
621 );
622 if (EFI_ERROR (Status)) {
623 //
624 // If an error occurs allocating the pages for the current memory type, then
625 // free all the pages allocates for the previous memory types and return. This
626 // operation with be retied when/if more memory is added to the system
627 //
628 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
629 //
630 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
631 //
632 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
633 if ((UINT32)Type > EfiMaxMemoryType) {
634 continue;
635 }
636
637 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
638 CoreFreePages (
639 mMemoryTypeStatistics[Type].BaseAddress,
640 gMemoryTypeInformation[FreeIndex].NumberOfPages
641 );
642 mMemoryTypeStatistics[Type].BaseAddress = 0;
643 mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;
644 }
645 }
646 return;
647 }
648
649 //
650 // Compute the address at the top of the current statistics
651 //
652 mMemoryTypeStatistics[Type].MaximumAddress =
653 mMemoryTypeStatistics[Type].BaseAddress +
654 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
655
656 //
657 // If the current base address is the lowest address so far, then update the default
658 // maximum address
659 //
660 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
661 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
662 }
663 }
664 }
665
666 //
667 // There was enough system memory for all the the memory types were allocated. So,
668 // those memory areas can be freed for future allocations, and all future memory
669 // allocations can occur within their respective bins
670 //
671 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
672 //
673 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
674 //
675 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
676 if ((UINT32)Type > EfiMaxMemoryType) {
677 continue;
678 }
679 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
680 CoreFreePages (
681 mMemoryTypeStatistics[Type].BaseAddress,
682 gMemoryTypeInformation[Index].NumberOfPages
683 );
684 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
685 gMemoryTypeInformation[Index].NumberOfPages = 0;
686 }
687 }
688
689 //
690 // If the number of pages reserved for a memory type is 0, then all allocations for that type
691 // should be in the default range.
692 //
693 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
694 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
695 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
696 mMemoryTypeStatistics[Type].InformationIndex = Index;
697 }
698 }
699 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
700 if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {
701 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
702 }
703 }
704
705 mMemoryTypeInformationInitialized = TRUE;
706 }
707
708
709 /**
710 Internal function. Converts a memory range to the specified type or attributes.
711 The range must exist in the memory map. Either ChangingType or
712 ChangingAttributes must be set, but not both.
713
714 @param Start The first address of the range Must be page
715 aligned
716 @param NumberOfPages The number of pages to convert
717 @param ChangingType Boolean indicating that type value should be changed
718 @param NewType The new type for the memory range
719 @param ChangingAttributes Boolean indicating that attributes value should be changed
720 @param NewAttributes The new attributes for the memory range
721
722 @retval EFI_INVALID_PARAMETER Invalid parameter
723 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
724 range or convertion not allowed.
725 @retval EFI_SUCCESS Successfully converts the memory range to the
726 specified type.
727
728 **/
729 EFI_STATUS
730 CoreConvertPagesEx (
731 IN UINT64 Start,
732 IN UINT64 NumberOfPages,
733 IN BOOLEAN ChangingType,
734 IN EFI_MEMORY_TYPE NewType,
735 IN BOOLEAN ChangingAttributes,
736 IN UINT64 NewAttributes
737 )
738 {
739
740 UINT64 NumberOfBytes;
741 UINT64 End;
742 UINT64 RangeEnd;
743 UINT64 Attribute;
744 EFI_MEMORY_TYPE MemType;
745 LIST_ENTRY *Link;
746 MEMORY_MAP *Entry;
747
748 Entry = NULL;
749 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
750 End = Start + NumberOfBytes - 1;
751
752 ASSERT (NumberOfPages);
753 ASSERT ((Start & EFI_PAGE_MASK) == 0);
754 ASSERT (End > Start) ;
755 ASSERT_LOCKED (&gMemoryLock);
756 ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );
757
758 if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
759 return EFI_INVALID_PARAMETER;
760 }
761
762 //
763 // Convert the entire range
764 //
765
766 while (Start < End) {
767
768 //
769 // Find the entry that the covers the range
770 //
771 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
772 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
773
774 if (Entry->Start <= Start && Entry->End > Start) {
775 break;
776 }
777 }
778
779 if (Link == &gMemoryMap) {
780 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
781 return EFI_NOT_FOUND;
782 }
783
784 //
785 // If we are converting the type of the range from EfiConventionalMemory to
786 // another type, we have to ensure that the entire range is covered by a
787 // single entry.
788 //
789 if (ChangingType && (NewType != EfiConventionalMemory)) {
790 if (Entry->End < End) {
791 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));
792 return EFI_NOT_FOUND;
793 }
794 }
795 //
796 // Convert range to the end, or to the end of the descriptor
797 // if that's all we've got
798 //
799 RangeEnd = End;
800
801 ASSERT (Entry != NULL);
802 if (Entry->End < End) {
803 RangeEnd = Entry->End;
804 }
805
806 if (ChangingType) {
807 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
808 }
809 if (ChangingAttributes) {
810 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
811 }
812
813 if (ChangingType) {
814 //
815 // Debug code - verify conversion is allowed
816 //
817 if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
818 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));
819 if (Entry->Type == EfiConventionalMemory) {
820 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));
821 } else {
822 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));
823 }
824 return EFI_NOT_FOUND;
825 }
826
827 //
828 // Update counters for the number of pages allocated to each memory type
829 //
830 if ((UINT32)Entry->Type < EfiMaxMemoryType) {
831 if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
832 (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
833 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
834 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
835 } else {
836 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
837 }
838 }
839 }
840
841 if ((UINT32)NewType < EfiMaxMemoryType) {
842 if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
843 (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
844 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
845 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
846 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
847 }
848 }
849 }
850 }
851
852 //
853 // Pull range out of descriptor
854 //
855 if (Entry->Start == Start) {
856
857 //
858 // Clip start
859 //
860 Entry->Start = RangeEnd + 1;
861
862 } else if (Entry->End == RangeEnd) {
863
864 //
865 // Clip end
866 //
867 Entry->End = Start - 1;
868
869 } else {
870
871 //
872 // Pull it out of the center, clip current
873 //
874
875 //
876 // Add a new one
877 //
878 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
879 mMapStack[mMapDepth].FromPages = FALSE;
880 mMapStack[mMapDepth].Type = Entry->Type;
881 mMapStack[mMapDepth].Start = RangeEnd+1;
882 mMapStack[mMapDepth].End = Entry->End;
883
884 //
885 // Inherit Attribute from the Memory Descriptor that is being clipped
886 //
887 mMapStack[mMapDepth].Attribute = Entry->Attribute;
888
889 Entry->End = Start - 1;
890 ASSERT (Entry->Start < Entry->End);
891
892 Entry = &mMapStack[mMapDepth];
893 InsertTailList (&gMemoryMap, &Entry->Link);
894
895 mMapDepth += 1;
896 ASSERT (mMapDepth < MAX_MAP_DEPTH);
897 }
898
899 //
900 // The new range inherits the same Attribute as the Entry
901 // it is being cut out of unless attributes are being changed
902 //
903 if (ChangingType) {
904 Attribute = Entry->Attribute;
905 MemType = NewType;
906 } else {
907 Attribute = NewAttributes;
908 MemType = Entry->Type;
909 }
910
911 //
912 // If the descriptor is empty, then remove it from the map
913 //
914 if (Entry->Start == Entry->End + 1) {
915 RemoveMemoryMapEntry (Entry);
916 Entry = NULL;
917 }
918
919 //
920 // Add our new range in. Don't do this for freed pages if freed-memory
921 // guard is enabled.
922 //
923 if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
924 !ChangingType ||
925 MemType != EfiConventionalMemory) {
926 CoreAddRange (MemType, Start, RangeEnd, Attribute);
927 }
928
929 if (ChangingType && (MemType == EfiConventionalMemory)) {
930 //
931 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
932 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
933 // that the page starting at address 0 is always filled with zeros.
934 //
935 if (Start == 0) {
936 if (RangeEnd > EFI_PAGE_SIZE) {
937 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
938 }
939 } else {
940 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));
941 }
942 }
943
944 //
945 // Move any map descriptor stack to general pool
946 //
947 CoreFreeMemoryMapStack ();
948
949 //
950 // Bump the starting address, and convert the next range
951 //
952 Start = RangeEnd + 1;
953 }
954
955 //
956 // Converted the whole range, done
957 //
958
959 return EFI_SUCCESS;
960 }
961
962
963 /**
964 Internal function. Converts a memory range to the specified type.
965 The range must exist in the memory map.
966
967 @param Start The first address of the range Must be page
968 aligned
969 @param NumberOfPages The number of pages to convert
970 @param NewType The new type for the memory range
971
972 @retval EFI_INVALID_PARAMETER Invalid parameter
973 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
974 range or convertion not allowed.
975 @retval EFI_SUCCESS Successfully converts the memory range to the
976 specified type.
977
978 **/
979 EFI_STATUS
980 CoreConvertPages (
981 IN UINT64 Start,
982 IN UINT64 NumberOfPages,
983 IN EFI_MEMORY_TYPE NewType
984 )
985 {
986 return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
987 }
988
989
990 /**
991 Internal function. Converts a memory range to use new attributes.
992
993 @param Start The first address of the range Must be page
994 aligned
995 @param NumberOfPages The number of pages to convert
996 @param NewAttributes The new attributes value for the range.
997
998 **/
999 VOID
1000 CoreUpdateMemoryAttributes (
1001 IN EFI_PHYSICAL_ADDRESS Start,
1002 IN UINT64 NumberOfPages,
1003 IN UINT64 NewAttributes
1004 )
1005 {
1006 CoreAcquireMemoryLock ();
1007
1008 //
1009 // Update the attributes to the new value
1010 //
1011 CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
1012
1013 CoreReleaseMemoryLock ();
1014 }
1015
1016
1017 /**
1018 Internal function. Finds a consecutive free page range below
1019 the requested address.
1020
1021 @param MaxAddress The address that the range must be below
1022 @param MinAddress The address that the range must be above
1023 @param NumberOfPages Number of pages needed
1024 @param NewType The type of memory the range is going to be
1025 turned into
1026 @param Alignment Bits to align with
1027 @param NeedGuard Flag to indicate Guard page is needed or not
1028
1029 @return The base address of the range, or 0 if the range was not found
1030
1031 **/
1032 UINT64
1033 CoreFindFreePagesI (
1034 IN UINT64 MaxAddress,
1035 IN UINT64 MinAddress,
1036 IN UINT64 NumberOfPages,
1037 IN EFI_MEMORY_TYPE NewType,
1038 IN UINTN Alignment,
1039 IN BOOLEAN NeedGuard
1040 )
1041 {
1042 UINT64 NumberOfBytes;
1043 UINT64 Target;
1044 UINT64 DescStart;
1045 UINT64 DescEnd;
1046 UINT64 DescNumberOfBytes;
1047 LIST_ENTRY *Link;
1048 MEMORY_MAP *Entry;
1049
1050 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
1051 return 0;
1052 }
1053
1054 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
1055
1056 //
1057 // If MaxAddress is not aligned to the end of a page
1058 //
1059
1060 //
1061 // Change MaxAddress to be 1 page lower
1062 //
1063 MaxAddress -= (EFI_PAGE_MASK + 1);
1064
1065 //
1066 // Set MaxAddress to a page boundary
1067 //
1068 MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
1069
1070 //
1071 // Set MaxAddress to end of the page
1072 //
1073 MaxAddress |= EFI_PAGE_MASK;
1074 }
1075
1076 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1077 Target = 0;
1078
1079 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1080 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1081
1082 //
1083 // If it's not a free entry, don't bother with it
1084 //
1085 if (Entry->Type != EfiConventionalMemory) {
1086 continue;
1087 }
1088
1089 DescStart = Entry->Start;
1090 DescEnd = Entry->End;
1091
1092 //
1093 // If desc is past max allowed address or below min allowed address, skip it
1094 //
1095 if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
1096 continue;
1097 }
1098
1099 //
1100 // If desc ends past max allowed address, clip the end
1101 //
1102 if (DescEnd >= MaxAddress) {
1103 DescEnd = MaxAddress;
1104 }
1105
1106 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
1107
1108 // Skip if DescEnd is less than DescStart after alignment clipping
1109 if (DescEnd < DescStart) {
1110 continue;
1111 }
1112
1113 //
1114 // Compute the number of bytes we can used from this
1115 // descriptor, and see it's enough to satisfy the request
1116 //
1117 DescNumberOfBytes = DescEnd - DescStart + 1;
1118
1119 if (DescNumberOfBytes >= NumberOfBytes) {
1120 //
1121 // If the start of the allocated range is below the min address allowed, skip it
1122 //
1123 if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
1124 continue;
1125 }
1126
1127 //
1128 // If this is the best match so far remember it
1129 //
1130 if (DescEnd > Target) {
1131 if (NeedGuard) {
1132 DescEnd = AdjustMemoryS (
1133 DescEnd + 1 - DescNumberOfBytes,
1134 DescNumberOfBytes,
1135 NumberOfBytes
1136 );
1137 if (DescEnd == 0) {
1138 continue;
1139 }
1140 }
1141
1142 Target = DescEnd;
1143 }
1144 }
1145 }
1146
1147 //
1148 // If this is a grow down, adjust target to be the allocation base
1149 //
1150 Target -= NumberOfBytes - 1;
1151
1152 //
1153 // If we didn't find a match, return 0
1154 //
1155 if ((Target & EFI_PAGE_MASK) != 0) {
1156 return 0;
1157 }
1158
1159 return Target;
1160 }
1161
1162
1163 /**
1164 Internal function. Finds a consecutive free page range below
1165 the requested address
1166
1167 @param MaxAddress The address that the range must be below
1168 @param NoPages Number of pages needed
1169 @param NewType The type of memory the range is going to be
1170 turned into
1171 @param Alignment Bits to align with
1172 @param NeedGuard Flag to indicate Guard page is needed or not
1173
1174 @return The base address of the range, or 0 if the range was not found.
1175
1176 **/
1177 UINT64
1178 FindFreePages (
1179 IN UINT64 MaxAddress,
1180 IN UINT64 NoPages,
1181 IN EFI_MEMORY_TYPE NewType,
1182 IN UINTN Alignment,
1183 IN BOOLEAN NeedGuard
1184 )
1185 {
1186 UINT64 Start;
1187
1188 //
1189 // Attempt to find free pages in the preferred bin based on the requested memory type
1190 //
1191 if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
1192 Start = CoreFindFreePagesI (
1193 mMemoryTypeStatistics[NewType].MaximumAddress,
1194 mMemoryTypeStatistics[NewType].BaseAddress,
1195 NoPages,
1196 NewType,
1197 Alignment,
1198 NeedGuard
1199 );
1200 if (Start != 0) {
1201 return Start;
1202 }
1203 }
1204
1205 //
1206 // Attempt to find free pages in the default allocation bin
1207 //
1208 if (MaxAddress >= mDefaultMaximumAddress) {
1209 Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,
1210 Alignment, NeedGuard);
1211 if (Start != 0) {
1212 if (Start < mDefaultBaseAddress) {
1213 mDefaultBaseAddress = Start;
1214 }
1215 return Start;
1216 }
1217 }
1218
1219 //
1220 // The allocation did not succeed in any of the prefered bins even after
1221 // promoting resources. Attempt to find free pages anywhere is the requested
1222 // address range. If this allocation fails, then there are not enough
1223 // resources anywhere to satisfy the request.
1224 //
1225 Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,
1226 NeedGuard);
1227 if (Start != 0) {
1228 return Start;
1229 }
1230
1231 //
1232 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1233 //
1234 if (!PromoteMemoryResource ()) {
1235 return 0;
1236 }
1237
1238 //
1239 // If any memory resources were promoted, then re-attempt the allocation
1240 //
1241 return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
1242 }
1243
1244
1245 /**
1246 Allocates pages from the memory map.
1247
1248 @param Type The type of allocation to perform
1249 @param MemoryType The type of memory to turn the allocated pages
1250 into
1251 @param NumberOfPages The number of pages to allocate
1252 @param Memory A pointer to receive the base allocated memory
1253 address
1254 @param NeedGuard Flag to indicate Guard page is needed or not
1255
1256 @return Status. On success, Memory is filled in with the base address allocated
1257 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1258 spec.
1259 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1260 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1261 @retval EFI_SUCCESS Pages successfully allocated.
1262
1263 **/
1264 EFI_STATUS
1265 EFIAPI
1266 CoreInternalAllocatePages (
1267 IN EFI_ALLOCATE_TYPE Type,
1268 IN EFI_MEMORY_TYPE MemoryType,
1269 IN UINTN NumberOfPages,
1270 IN OUT EFI_PHYSICAL_ADDRESS *Memory,
1271 IN BOOLEAN NeedGuard
1272 )
1273 {
1274 EFI_STATUS Status;
1275 UINT64 Start;
1276 UINT64 NumberOfBytes;
1277 UINT64 End;
1278 UINT64 MaxAddress;
1279 UINTN Alignment;
1280
1281 if ((UINT32)Type >= MaxAllocateType) {
1282 return EFI_INVALID_PARAMETER;
1283 }
1284
1285 if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
1286 (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1287 return EFI_INVALID_PARAMETER;
1288 }
1289
1290 if (Memory == NULL) {
1291 return EFI_INVALID_PARAMETER;
1292 }
1293
1294 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1295
1296 if (MemoryType == EfiACPIReclaimMemory ||
1297 MemoryType == EfiACPIMemoryNVS ||
1298 MemoryType == EfiRuntimeServicesCode ||
1299 MemoryType == EfiRuntimeServicesData) {
1300
1301 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1302 }
1303
1304 if (Type == AllocateAddress) {
1305 if ((*Memory & (Alignment - 1)) != 0) {
1306 return EFI_NOT_FOUND;
1307 }
1308 }
1309
1310 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1311 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1312
1313 //
1314 // If this is for below a particular address, then
1315 //
1316 Start = *Memory;
1317
1318 //
1319 // The max address is the max natively addressable address for the processor
1320 //
1321 MaxAddress = MAX_ALLOC_ADDRESS;
1322
1323 //
1324 // Check for Type AllocateAddress,
1325 // if NumberOfPages is 0 or
1326 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or
1327 // if (Start + NumberOfBytes) rolls over 0 or
1328 // if Start is above MAX_ALLOC_ADDRESS or
1329 // if End is above MAX_ALLOC_ADDRESS,
1330 // return EFI_NOT_FOUND.
1331 //
1332 if (Type == AllocateAddress) {
1333 if ((NumberOfPages == 0) ||
1334 (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) {
1335 return EFI_NOT_FOUND;
1336 }
1337 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1338 End = Start + NumberOfBytes - 1;
1339
1340 if ((Start >= End) ||
1341 (Start > MaxAddress) ||
1342 (End > MaxAddress)) {
1343 return EFI_NOT_FOUND;
1344 }
1345 }
1346
1347 if (Type == AllocateMaxAddress) {
1348 MaxAddress = Start;
1349 }
1350
1351 CoreAcquireMemoryLock ();
1352
1353 //
1354 // If not a specific address, then find an address to allocate
1355 //
1356 if (Type != AllocateAddress) {
1357 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
1358 NeedGuard);
1359 if (Start == 0) {
1360 Status = EFI_OUT_OF_RESOURCES;
1361 goto Done;
1362 }
1363 }
1364
1365 //
1366 // Convert pages from FreeMemory to the requested type
1367 //
1368 if (NeedGuard) {
1369 Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
1370 } else {
1371 Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
1372 }
1373
1374 Done:
1375 CoreReleaseMemoryLock ();
1376
1377 if (!EFI_ERROR (Status)) {
1378 if (NeedGuard) {
1379 SetGuardForMemory (Start, NumberOfPages);
1380 }
1381 *Memory = Start;
1382 }
1383
1384 return Status;
1385 }
1386
1387 /**
1388 Allocates pages from the memory map.
1389
1390 @param Type The type of allocation to perform
1391 @param MemoryType The type of memory to turn the allocated pages
1392 into
1393 @param NumberOfPages The number of pages to allocate
1394 @param Memory A pointer to receive the base allocated memory
1395 address
1396
1397 @return Status. On success, Memory is filled in with the base address allocated
1398 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1399 spec.
1400 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1401 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1402 @retval EFI_SUCCESS Pages successfully allocated.
1403
1404 **/
1405 EFI_STATUS
1406 EFIAPI
1407 CoreAllocatePages (
1408 IN EFI_ALLOCATE_TYPE Type,
1409 IN EFI_MEMORY_TYPE MemoryType,
1410 IN UINTN NumberOfPages,
1411 OUT EFI_PHYSICAL_ADDRESS *Memory
1412 )
1413 {
1414 EFI_STATUS Status;
1415 BOOLEAN NeedGuard;
1416
1417 NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
1418 Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
1419 NeedGuard);
1420 if (!EFI_ERROR (Status)) {
1421 CoreUpdateProfile (
1422 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1423 MemoryProfileActionAllocatePages,
1424 MemoryType,
1425 EFI_PAGES_TO_SIZE (NumberOfPages),
1426 (VOID *) (UINTN) *Memory,
1427 NULL
1428 );
1429 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
1430 ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
1431 EFI_PAGES_TO_SIZE (NumberOfPages));
1432 }
1433 return Status;
1434 }
1435
1436 /**
1437 Frees previous allocated pages.
1438
1439 @param Memory Base address of memory being freed
1440 @param NumberOfPages The number of pages to free
1441 @param MemoryType Pointer to memory type
1442
1443 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1444 @retval EFI_INVALID_PARAMETER Address not aligned
1445 @return EFI_SUCCESS -Pages successfully freed.
1446
1447 **/
1448 EFI_STATUS
1449 EFIAPI
1450 CoreInternalFreePages (
1451 IN EFI_PHYSICAL_ADDRESS Memory,
1452 IN UINTN NumberOfPages,
1453 OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL
1454 )
1455 {
1456 EFI_STATUS Status;
1457 LIST_ENTRY *Link;
1458 MEMORY_MAP *Entry;
1459 UINTN Alignment;
1460 BOOLEAN IsGuarded;
1461
1462 //
1463 // Free the range
1464 //
1465 CoreAcquireMemoryLock ();
1466
1467 //
1468 // Find the entry that the covers the range
1469 //
1470 IsGuarded = FALSE;
1471 Entry = NULL;
1472 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1473 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1474 if (Entry->Start <= Memory && Entry->End > Memory) {
1475 break;
1476 }
1477 }
1478 if (Link == &gMemoryMap) {
1479 Status = EFI_NOT_FOUND;
1480 goto Done;
1481 }
1482
1483 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
1484
1485 ASSERT (Entry != NULL);
1486 if (Entry->Type == EfiACPIReclaimMemory ||
1487 Entry->Type == EfiACPIMemoryNVS ||
1488 Entry->Type == EfiRuntimeServicesCode ||
1489 Entry->Type == EfiRuntimeServicesData) {
1490
1491 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
1492
1493 }
1494
1495 if ((Memory & (Alignment - 1)) != 0) {
1496 Status = EFI_INVALID_PARAMETER;
1497 goto Done;
1498 }
1499
1500 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1501 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1502
1503 if (MemoryType != NULL) {
1504 *MemoryType = Entry->Type;
1505 }
1506
1507 IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
1508 IsMemoryGuarded (Memory);
1509 if (IsGuarded) {
1510 Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
1511 EfiConventionalMemory);
1512 } else {
1513 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1514 }
1515
1516 Done:
1517 CoreReleaseMemoryLock ();
1518 return Status;
1519 }
1520
1521 /**
1522 Frees previous allocated pages.
1523
1524 @param Memory Base address of memory being freed
1525 @param NumberOfPages The number of pages to free
1526
1527 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1528 @retval EFI_INVALID_PARAMETER Address not aligned
1529 @return EFI_SUCCESS -Pages successfully freed.
1530
1531 **/
1532 EFI_STATUS
1533 EFIAPI
1534 CoreFreePages (
1535 IN EFI_PHYSICAL_ADDRESS Memory,
1536 IN UINTN NumberOfPages
1537 )
1538 {
1539 EFI_STATUS Status;
1540 EFI_MEMORY_TYPE MemoryType;
1541
1542 Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);
1543 if (!EFI_ERROR (Status)) {
1544 GuardFreedPagesChecked (Memory, NumberOfPages);
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 DumpGuardedMemoryBitmap ();
1940 );
1941
1942 return Status;
1943 }
1944
1945
1946 /**
1947 Internal function. Used by the pool functions to allocate pages
1948 to back pool allocation requests.
1949
1950 @param PoolType The type of memory for the new pool pages
1951 @param NumberOfPages No of pages to allocate
1952 @param Alignment Bits to align.
1953 @param NeedGuard Flag to indicate Guard page is needed or not
1954
1955 @return The allocated memory, or NULL
1956
1957 **/
1958 VOID *
1959 CoreAllocatePoolPages (
1960 IN EFI_MEMORY_TYPE PoolType,
1961 IN UINTN NumberOfPages,
1962 IN UINTN Alignment,
1963 IN BOOLEAN NeedGuard
1964 )
1965 {
1966 UINT64 Start;
1967
1968 //
1969 // Find the pages to convert
1970 //
1971 Start = FindFreePages (MAX_ALLOC_ADDRESS, NumberOfPages, PoolType, Alignment,
1972 NeedGuard);
1973
1974 //
1975 // Convert it to boot services data
1976 //
1977 if (Start == 0) {
1978 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1979 } else {
1980 if (NeedGuard) {
1981 CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
1982 } else {
1983 CoreConvertPages (Start, NumberOfPages, PoolType);
1984 }
1985 }
1986
1987 return (VOID *)(UINTN) Start;
1988 }
1989
1990
1991 /**
1992 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1993
1994 @param Memory The base address to free
1995 @param NumberOfPages The number of pages to free
1996
1997 **/
1998 VOID
1999 CoreFreePoolPages (
2000 IN EFI_PHYSICAL_ADDRESS Memory,
2001 IN UINTN NumberOfPages
2002 )
2003 {
2004 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
2005 }
2006
2007
2008
2009 /**
2010 Make sure the memory map is following all the construction rules,
2011 it is the last time to check memory map error before exit boot services.
2012
2013 @param MapKey Memory map key
2014
2015 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
2016 rules.
2017 @retval EFI_SUCCESS Valid memory map.
2018
2019 **/
2020 EFI_STATUS
2021 CoreTerminateMemoryMap (
2022 IN UINTN MapKey
2023 )
2024 {
2025 EFI_STATUS Status;
2026 LIST_ENTRY *Link;
2027 MEMORY_MAP *Entry;
2028
2029 Status = EFI_SUCCESS;
2030
2031 CoreAcquireMemoryLock ();
2032
2033 if (MapKey == mMemoryMapKey) {
2034
2035 //
2036 // Make sure the memory map is following all the construction rules
2037 // This is the last chance we will be able to display any messages on
2038 // the console devices.
2039 //
2040
2041 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
2042 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
2043 if (Entry->Type < EfiMaxMemoryType) {
2044 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
2045 ASSERT (Entry->Type != EfiACPIReclaimMemory);
2046 ASSERT (Entry->Type != EfiACPIMemoryNVS);
2047 if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2048 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2049 Status = EFI_INVALID_PARAMETER;
2050 goto Done;
2051 }
2052 if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
2053 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
2054 Status = EFI_INVALID_PARAMETER;
2055 goto Done;
2056 }
2057 }
2058 }
2059 }
2060
2061 //
2062 // The map key they gave us matches what we expect. Fall through and
2063 // return success. In an ideal world we would clear out all of
2064 // EfiBootServicesCode and EfiBootServicesData. However this function
2065 // is not the last one called by ExitBootServices(), so we have to
2066 // preserve the memory contents.
2067 //
2068 } else {
2069 Status = EFI_INVALID_PARAMETER;
2070 }
2071
2072 Done:
2073 CoreReleaseMemoryLock ();
2074
2075 return Status;
2076 }
2077
2078
2079
2080
2081
2082
2083
2084
2085