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