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