]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
MdePkg UefiSpec.h: Update comments for OEM reserved memory type.
[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 if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {
420 Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
421 } else {
422 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
423 }
424 Entry->Capabilities |= EFI_MEMORY_TESTED;
425 Entry->ImageHandle = gDxeCoreImageHandle;
426 Entry->DeviceHandle = NULL;
427
428 //
429 // Add to allocable system memory resource
430 //
431
432 CoreAddRange (
433 EfiConventionalMemory,
434 Entry->BaseAddress,
435 Entry->EndAddress,
436 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
437 );
438 CoreFreeMemoryMapStack ();
439
440 Promoted = TRUE;
441 }
442
443 Link = Link->ForwardLink;
444 }
445
446 CoreReleaseGcdMemoryLock ();
447
448 return Promoted;
449 }
450 /**
451 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
452 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
453 size of boot time and runtime code.
454
455 **/
456 VOID
457 CoreLoadingFixedAddressHook (
458 VOID
459 )
460 {
461 UINT32 RuntimeCodePageNumber;
462 UINT32 BootTimeCodePageNumber;
463 EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
464 EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
465 EFI_STATUS Status;
466
467 //
468 // Make sure these 2 areas are not initialzied.
469 //
470 if (!gLoadFixedAddressCodeMemoryReady) {
471 RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
472 BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
473 RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
474 BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
475 //
476 // Try to allocate runtime memory.
477 //
478 Status = CoreAllocatePages (
479 AllocateAddress,
480 EfiRuntimeServicesCode,
481 RuntimeCodePageNumber,
482 &RuntimeCodeBase
483 );
484 if (EFI_ERROR(Status)) {
485 //
486 // Runtime memory allocation failed
487 //
488 return;
489 }
490 //
491 // Try to allocate boot memory.
492 //
493 Status = CoreAllocatePages (
494 AllocateAddress,
495 EfiBootServicesCode,
496 BootTimeCodePageNumber,
497 &BootTimeCodeBase
498 );
499 if (EFI_ERROR(Status)) {
500 //
501 // boot memory allocation failed. Free Runtime code range and will try the allocation again when
502 // new memory range is installed.
503 //
504 CoreFreePages (
505 RuntimeCodeBase,
506 RuntimeCodePageNumber
507 );
508 return;
509 }
510 gLoadFixedAddressCodeMemoryReady = TRUE;
511 }
512 return;
513 }
514
515 /**
516 Called to initialize the memory map and add descriptors to
517 the current descriptor list.
518 The first descriptor that is added must be general usable
519 memory as the addition allocates heap.
520
521 @param Type The type of memory to add
522 @param Start The starting address in the memory range Must be
523 page aligned
524 @param NumberOfPages The number of pages in the range
525 @param Attribute Attributes of the memory to add
526
527 @return None. The range is added to the memory map
528
529 **/
530 VOID
531 CoreAddMemoryDescriptor (
532 IN EFI_MEMORY_TYPE Type,
533 IN EFI_PHYSICAL_ADDRESS Start,
534 IN UINT64 NumberOfPages,
535 IN UINT64 Attribute
536 )
537 {
538 EFI_PHYSICAL_ADDRESS End;
539 EFI_STATUS Status;
540 UINTN Index;
541 UINTN FreeIndex;
542
543 if ((Start & EFI_PAGE_MASK) != 0) {
544 return;
545 }
546
547 if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {
548 return;
549 }
550 CoreAcquireMemoryLock ();
551 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
552 CoreAddRange (Type, Start, End, Attribute);
553 CoreFreeMemoryMapStack ();
554 CoreReleaseMemoryLock ();
555
556 //
557 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
558 //
559 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
560 CoreLoadingFixedAddressHook();
561 }
562
563 //
564 // Check to see if the statistics for the different memory types have already been established
565 //
566 if (mMemoryTypeInformationInitialized) {
567 return;
568 }
569
570
571 //
572 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
573 //
574 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
575 //
576 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
577 //
578 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
579 if ((UINT32)Type > EfiMaxMemoryType) {
580 continue;
581 }
582 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
583 //
584 // Allocate pages for the current memory type from the top of available memory
585 //
586 Status = CoreAllocatePages (
587 AllocateAnyPages,
588 Type,
589 gMemoryTypeInformation[Index].NumberOfPages,
590 &mMemoryTypeStatistics[Type].BaseAddress
591 );
592 if (EFI_ERROR (Status)) {
593 //
594 // If an error occurs allocating the pages for the current memory type, then
595 // free all the pages allocates for the previous memory types and return. This
596 // operation with be retied when/if more memory is added to the system
597 //
598 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
599 //
600 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
601 //
602 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
603 if ((UINT32)Type > EfiMaxMemoryType) {
604 continue;
605 }
606
607 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
608 CoreFreePages (
609 mMemoryTypeStatistics[Type].BaseAddress,
610 gMemoryTypeInformation[FreeIndex].NumberOfPages
611 );
612 mMemoryTypeStatistics[Type].BaseAddress = 0;
613 mMemoryTypeStatistics[Type].MaximumAddress = MAX_ADDRESS;
614 }
615 }
616 return;
617 }
618
619 //
620 // Compute the address at the top of the current statistics
621 //
622 mMemoryTypeStatistics[Type].MaximumAddress =
623 mMemoryTypeStatistics[Type].BaseAddress +
624 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
625
626 //
627 // If the current base address is the lowest address so far, then update the default
628 // maximum address
629 //
630 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
631 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
632 }
633 }
634 }
635
636 //
637 // There was enough system memory for all the the memory types were allocated. So,
638 // those memory areas can be freed for future allocations, and all future memory
639 // allocations can occur within their respective bins
640 //
641 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
642 //
643 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
644 //
645 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
646 if ((UINT32)Type > EfiMaxMemoryType) {
647 continue;
648 }
649 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
650 CoreFreePages (
651 mMemoryTypeStatistics[Type].BaseAddress,
652 gMemoryTypeInformation[Index].NumberOfPages
653 );
654 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
655 gMemoryTypeInformation[Index].NumberOfPages = 0;
656 }
657 }
658
659 //
660 // If the number of pages reserved for a memory type is 0, then all allocations for that type
661 // should be in the default range.
662 //
663 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
664 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
665 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
666 mMemoryTypeStatistics[Type].InformationIndex = Index;
667 }
668 }
669 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
670 if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ADDRESS) {
671 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
672 }
673 }
674
675 mMemoryTypeInformationInitialized = TRUE;
676 }
677
678
679 /**
680 Internal function. Converts a memory range to the specified type or attributes.
681 The range must exist in the memory map. Either ChangingType or
682 ChangingAttributes must be set, but not both.
683
684 @param Start The first address of the range Must be page
685 aligned
686 @param NumberOfPages The number of pages to convert
687 @param ChangingType Boolean indicating that type value should be changed
688 @param NewType The new type for the memory range
689 @param ChangingAttributes Boolean indicating that attributes value should be changed
690 @param NewAttributes The new attributes for the memory range
691
692 @retval EFI_INVALID_PARAMETER Invalid parameter
693 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
694 range or convertion not allowed.
695 @retval EFI_SUCCESS Successfully converts the memory range to the
696 specified type.
697
698 **/
699 EFI_STATUS
700 CoreConvertPagesEx (
701 IN UINT64 Start,
702 IN UINT64 NumberOfPages,
703 IN BOOLEAN ChangingType,
704 IN EFI_MEMORY_TYPE NewType,
705 IN BOOLEAN ChangingAttributes,
706 IN UINT64 NewAttributes
707 )
708 {
709
710 UINT64 NumberOfBytes;
711 UINT64 End;
712 UINT64 RangeEnd;
713 UINT64 Attribute;
714 EFI_MEMORY_TYPE MemType;
715 LIST_ENTRY *Link;
716 MEMORY_MAP *Entry;
717
718 Entry = NULL;
719 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
720 End = Start + NumberOfBytes - 1;
721
722 ASSERT (NumberOfPages);
723 ASSERT ((Start & EFI_PAGE_MASK) == 0);
724 ASSERT (End > Start) ;
725 ASSERT_LOCKED (&gMemoryLock);
726 ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) );
727
728 if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) {
729 return EFI_INVALID_PARAMETER;
730 }
731
732 //
733 // Convert the entire range
734 //
735
736 while (Start < End) {
737
738 //
739 // Find the entry that the covers the range
740 //
741 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
742 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
743
744 if (Entry->Start <= Start && Entry->End > Start) {
745 break;
746 }
747 }
748
749 if (Link == &gMemoryMap) {
750 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
751 return EFI_NOT_FOUND;
752 }
753
754 //
755 // Convert range to the end, or to the end of the descriptor
756 // if that's all we've got
757 //
758 RangeEnd = End;
759
760 ASSERT (Entry != NULL);
761 if (Entry->End < End) {
762 RangeEnd = Entry->End;
763 }
764
765 if (ChangingType) {
766 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));
767 }
768 if (ChangingAttributes) {
769 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));
770 }
771
772 if (ChangingType) {
773 //
774 // Debug code - verify conversion is allowed
775 //
776 if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
777 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n"));
778 return EFI_NOT_FOUND;
779 }
780
781 //
782 // Update counters for the number of pages allocated to each memory type
783 //
784 if ((UINT32)Entry->Type < EfiMaxMemoryType) {
785 if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) ||
786 (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
787 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
788 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
789 } else {
790 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
791 }
792 }
793 }
794
795 if ((UINT32)NewType < EfiMaxMemoryType) {
796 if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) ||
797 (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) {
798 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
799 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
800 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
801 }
802 }
803 }
804 }
805
806 //
807 // Pull range out of descriptor
808 //
809 if (Entry->Start == Start) {
810
811 //
812 // Clip start
813 //
814 Entry->Start = RangeEnd + 1;
815
816 } else if (Entry->End == RangeEnd) {
817
818 //
819 // Clip end
820 //
821 Entry->End = Start - 1;
822
823 } else {
824
825 //
826 // Pull it out of the center, clip current
827 //
828
829 //
830 // Add a new one
831 //
832 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
833 mMapStack[mMapDepth].FromPages = FALSE;
834 mMapStack[mMapDepth].Type = Entry->Type;
835 mMapStack[mMapDepth].Start = RangeEnd+1;
836 mMapStack[mMapDepth].End = Entry->End;
837
838 //
839 // Inherit Attribute from the Memory Descriptor that is being clipped
840 //
841 mMapStack[mMapDepth].Attribute = Entry->Attribute;
842
843 Entry->End = Start - 1;
844 ASSERT (Entry->Start < Entry->End);
845
846 Entry = &mMapStack[mMapDepth];
847 InsertTailList (&gMemoryMap, &Entry->Link);
848
849 mMapDepth += 1;
850 ASSERT (mMapDepth < MAX_MAP_DEPTH);
851 }
852
853 //
854 // The new range inherits the same Attribute as the Entry
855 // it is being cut out of unless attributes are being changed
856 //
857 if (ChangingType) {
858 Attribute = Entry->Attribute;
859 MemType = NewType;
860 } else {
861 Attribute = NewAttributes;
862 MemType = Entry->Type;
863 }
864
865 //
866 // If the descriptor is empty, then remove it from the map
867 //
868 if (Entry->Start == Entry->End + 1) {
869 RemoveMemoryMapEntry (Entry);
870 Entry = NULL;
871 }
872
873 //
874 // Add our new range in
875 //
876 CoreAddRange (MemType, Start, RangeEnd, Attribute);
877 if (ChangingType && (MemType == EfiConventionalMemory)) {
878 //
879 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
880 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees
881 // that the page starting at address 0 is always filled with zeros.
882 //
883 if (Start == 0) {
884 if (RangeEnd > EFI_PAGE_SIZE) {
885 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));
886 }
887 } else {
888 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));
889 }
890 }
891
892 //
893 // Move any map descriptor stack to general pool
894 //
895 CoreFreeMemoryMapStack ();
896
897 //
898 // Bump the starting address, and convert the next range
899 //
900 Start = RangeEnd + 1;
901 }
902
903 //
904 // Converted the whole range, done
905 //
906
907 return EFI_SUCCESS;
908 }
909
910
911 /**
912 Internal function. Converts a memory range to the specified type.
913 The range must exist in the memory map.
914
915 @param Start The first address of the range Must be page
916 aligned
917 @param NumberOfPages The number of pages to convert
918 @param NewType The new type for the memory range
919
920 @retval EFI_INVALID_PARAMETER Invalid parameter
921 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
922 range or convertion not allowed.
923 @retval EFI_SUCCESS Successfully converts the memory range to the
924 specified type.
925
926 **/
927 EFI_STATUS
928 CoreConvertPages (
929 IN UINT64 Start,
930 IN UINT64 NumberOfPages,
931 IN EFI_MEMORY_TYPE NewType
932 )
933 {
934 return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0);
935 }
936
937
938 /**
939 Internal function. Converts a memory range to use new attributes.
940
941 @param Start The first address of the range Must be page
942 aligned
943 @param NumberOfPages The number of pages to convert
944 @param NewAttributes The new attributes value for the range.
945
946 **/
947 VOID
948 CoreUpdateMemoryAttributes (
949 IN EFI_PHYSICAL_ADDRESS Start,
950 IN UINT64 NumberOfPages,
951 IN UINT64 NewAttributes
952 )
953 {
954 CoreAcquireMemoryLock ();
955
956 //
957 // Update the attributes to the new value
958 //
959 CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);
960
961 CoreReleaseMemoryLock ();
962 }
963
964
965 /**
966 Internal function. Finds a consecutive free page range below
967 the requested address.
968
969 @param MaxAddress The address that the range must be below
970 @param MinAddress The address that the range must be above
971 @param NumberOfPages Number of pages needed
972 @param NewType The type of memory the range is going to be
973 turned into
974 @param Alignment Bits to align with
975
976 @return The base address of the range, or 0 if the range was not found
977
978 **/
979 UINT64
980 CoreFindFreePagesI (
981 IN UINT64 MaxAddress,
982 IN UINT64 MinAddress,
983 IN UINT64 NumberOfPages,
984 IN EFI_MEMORY_TYPE NewType,
985 IN UINTN Alignment
986 )
987 {
988 UINT64 NumberOfBytes;
989 UINT64 Target;
990 UINT64 DescStart;
991 UINT64 DescEnd;
992 UINT64 DescNumberOfBytes;
993 LIST_ENTRY *Link;
994 MEMORY_MAP *Entry;
995
996 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
997 return 0;
998 }
999
1000 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
1001
1002 //
1003 // If MaxAddress is not aligned to the end of a page
1004 //
1005
1006 //
1007 // Change MaxAddress to be 1 page lower
1008 //
1009 MaxAddress -= (EFI_PAGE_MASK + 1);
1010
1011 //
1012 // Set MaxAddress to a page boundary
1013 //
1014 MaxAddress &= ~(UINT64)EFI_PAGE_MASK;
1015
1016 //
1017 // Set MaxAddress to end of the page
1018 //
1019 MaxAddress |= EFI_PAGE_MASK;
1020 }
1021
1022 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
1023 Target = 0;
1024
1025 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1026 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1027
1028 //
1029 // If it's not a free entry, don't bother with it
1030 //
1031 if (Entry->Type != EfiConventionalMemory) {
1032 continue;
1033 }
1034
1035 DescStart = Entry->Start;
1036 DescEnd = Entry->End;
1037
1038 //
1039 // If desc is past max allowed address or below min allowed address, skip it
1040 //
1041 if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {
1042 continue;
1043 }
1044
1045 //
1046 // If desc ends past max allowed address, clip the end
1047 //
1048 if (DescEnd >= MaxAddress) {
1049 DescEnd = MaxAddress;
1050 }
1051
1052 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
1053
1054 //
1055 // Compute the number of bytes we can used from this
1056 // descriptor, and see it's enough to satisfy the request
1057 //
1058 DescNumberOfBytes = DescEnd - DescStart + 1;
1059
1060 if (DescNumberOfBytes >= NumberOfBytes) {
1061 //
1062 // If the start of the allocated range is below the min address allowed, skip it
1063 //
1064 if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
1065 continue;
1066 }
1067
1068 //
1069 // If this is the best match so far remember it
1070 //
1071 if (DescEnd > Target) {
1072 Target = DescEnd;
1073 }
1074 }
1075 }
1076
1077 //
1078 // If this is a grow down, adjust target to be the allocation base
1079 //
1080 Target -= NumberOfBytes - 1;
1081
1082 //
1083 // If we didn't find a match, return 0
1084 //
1085 if ((Target & EFI_PAGE_MASK) != 0) {
1086 return 0;
1087 }
1088
1089 return Target;
1090 }
1091
1092
1093 /**
1094 Internal function. Finds a consecutive free page range below
1095 the requested address
1096
1097 @param MaxAddress The address that the range must be below
1098 @param NoPages Number of pages needed
1099 @param NewType The type of memory the range is going to be
1100 turned into
1101 @param Alignment Bits to align with
1102
1103 @return The base address of the range, or 0 if the range was not found.
1104
1105 **/
1106 UINT64
1107 FindFreePages (
1108 IN UINT64 MaxAddress,
1109 IN UINT64 NoPages,
1110 IN EFI_MEMORY_TYPE NewType,
1111 IN UINTN Alignment
1112 )
1113 {
1114 UINT64 Start;
1115
1116 //
1117 // Attempt to find free pages in the preferred bin based on the requested memory type
1118 //
1119 if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
1120 Start = CoreFindFreePagesI (
1121 mMemoryTypeStatistics[NewType].MaximumAddress,
1122 mMemoryTypeStatistics[NewType].BaseAddress,
1123 NoPages,
1124 NewType,
1125 Alignment
1126 );
1127 if (Start != 0) {
1128 return Start;
1129 }
1130 }
1131
1132 //
1133 // Attempt to find free pages in the default allocation bin
1134 //
1135 if (MaxAddress >= mDefaultMaximumAddress) {
1136 Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, Alignment);
1137 if (Start != 0) {
1138 if (Start < mDefaultBaseAddress) {
1139 mDefaultBaseAddress = Start;
1140 }
1141 return Start;
1142 }
1143 }
1144
1145 //
1146 // The allocation did not succeed in any of the prefered bins even after
1147 // promoting resources. Attempt to find free pages anywhere is the requested
1148 // address range. If this allocation fails, then there are not enough
1149 // resources anywhere to satisfy the request.
1150 //
1151 Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment);
1152 if (Start != 0) {
1153 return Start;
1154 }
1155
1156 //
1157 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1158 //
1159 if (!PromoteMemoryResource ()) {
1160 return 0;
1161 }
1162
1163 //
1164 // If any memory resources were promoted, then re-attempt the allocation
1165 //
1166 return FindFreePages (MaxAddress, NoPages, NewType, Alignment);
1167 }
1168
1169
1170 /**
1171 Allocates pages from the memory map.
1172
1173 @param Type The type of allocation to perform
1174 @param MemoryType The type of memory to turn the allocated pages
1175 into
1176 @param NumberOfPages The number of pages to allocate
1177 @param Memory A pointer to receive the base allocated memory
1178 address
1179
1180 @return Status. On success, Memory is filled in with the base address allocated
1181 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1182 spec.
1183 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1184 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1185 @retval EFI_SUCCESS Pages successfully allocated.
1186
1187 **/
1188 EFI_STATUS
1189 EFIAPI
1190 CoreInternalAllocatePages (
1191 IN EFI_ALLOCATE_TYPE Type,
1192 IN EFI_MEMORY_TYPE MemoryType,
1193 IN UINTN NumberOfPages,
1194 IN OUT EFI_PHYSICAL_ADDRESS *Memory
1195 )
1196 {
1197 EFI_STATUS Status;
1198 UINT64 Start;
1199 UINT64 MaxAddress;
1200 UINTN Alignment;
1201
1202 if ((UINT32)Type >= MaxAllocateType) {
1203 return EFI_INVALID_PARAMETER;
1204 }
1205
1206 if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||
1207 (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1208 return EFI_INVALID_PARAMETER;
1209 }
1210
1211 if (Memory == NULL) {
1212 return EFI_INVALID_PARAMETER;
1213 }
1214
1215 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1216
1217 if (MemoryType == EfiACPIReclaimMemory ||
1218 MemoryType == EfiACPIMemoryNVS ||
1219 MemoryType == EfiRuntimeServicesCode ||
1220 MemoryType == EfiRuntimeServicesData) {
1221
1222 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1223 }
1224
1225 if (Type == AllocateAddress) {
1226 if ((*Memory & (Alignment - 1)) != 0) {
1227 return EFI_NOT_FOUND;
1228 }
1229 }
1230
1231 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1232 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1233
1234 //
1235 // If this is for below a particular address, then
1236 //
1237 Start = *Memory;
1238
1239 //
1240 // The max address is the max natively addressable address for the processor
1241 //
1242 MaxAddress = MAX_ADDRESS;
1243
1244 if (Type == AllocateMaxAddress) {
1245 MaxAddress = Start;
1246 }
1247
1248 CoreAcquireMemoryLock ();
1249
1250 //
1251 // If not a specific address, then find an address to allocate
1252 //
1253 if (Type != AllocateAddress) {
1254 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
1255 if (Start == 0) {
1256 Status = EFI_OUT_OF_RESOURCES;
1257 goto Done;
1258 }
1259 }
1260
1261 //
1262 // Convert pages from FreeMemory to the requested type
1263 //
1264 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
1265
1266 Done:
1267 CoreReleaseMemoryLock ();
1268
1269 if (!EFI_ERROR (Status)) {
1270 *Memory = Start;
1271 }
1272
1273 return Status;
1274 }
1275
1276 /**
1277 Allocates pages from the memory map.
1278
1279 @param Type The type of allocation to perform
1280 @param MemoryType The type of memory to turn the allocated pages
1281 into
1282 @param NumberOfPages The number of pages to allocate
1283 @param Memory A pointer to receive the base allocated memory
1284 address
1285
1286 @return Status. On success, Memory is filled in with the base address allocated
1287 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1288 spec.
1289 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1290 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1291 @retval EFI_SUCCESS Pages successfully allocated.
1292
1293 **/
1294 EFI_STATUS
1295 EFIAPI
1296 CoreAllocatePages (
1297 IN EFI_ALLOCATE_TYPE Type,
1298 IN EFI_MEMORY_TYPE MemoryType,
1299 IN UINTN NumberOfPages,
1300 OUT EFI_PHYSICAL_ADDRESS *Memory
1301 )
1302 {
1303 EFI_STATUS Status;
1304
1305 Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
1306 if (!EFI_ERROR (Status)) {
1307 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory);
1308 }
1309 return Status;
1310 }
1311
1312 /**
1313 Frees previous allocated pages.
1314
1315 @param Memory Base address of memory being freed
1316 @param NumberOfPages The number of pages to free
1317
1318 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1319 @retval EFI_INVALID_PARAMETER Address not aligned
1320 @return EFI_SUCCESS -Pages successfully freed.
1321
1322 **/
1323 EFI_STATUS
1324 EFIAPI
1325 CoreInternalFreePages (
1326 IN EFI_PHYSICAL_ADDRESS Memory,
1327 IN UINTN NumberOfPages
1328 )
1329 {
1330 EFI_STATUS Status;
1331 LIST_ENTRY *Link;
1332 MEMORY_MAP *Entry;
1333 UINTN Alignment;
1334
1335 //
1336 // Free the range
1337 //
1338 CoreAcquireMemoryLock ();
1339
1340 //
1341 // Find the entry that the covers the range
1342 //
1343 Entry = NULL;
1344 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1345 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1346 if (Entry->Start <= Memory && Entry->End > Memory) {
1347 break;
1348 }
1349 }
1350 if (Link == &gMemoryMap) {
1351 Status = EFI_NOT_FOUND;
1352 goto Done;
1353 }
1354
1355 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1356
1357 ASSERT (Entry != NULL);
1358 if (Entry->Type == EfiACPIReclaimMemory ||
1359 Entry->Type == EfiACPIMemoryNVS ||
1360 Entry->Type == EfiRuntimeServicesCode ||
1361 Entry->Type == EfiRuntimeServicesData) {
1362
1363 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1364
1365 }
1366
1367 if ((Memory & (Alignment - 1)) != 0) {
1368 Status = EFI_INVALID_PARAMETER;
1369 goto Done;
1370 }
1371
1372 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1373 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1374
1375 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1376
1377 if (EFI_ERROR (Status)) {
1378 goto Done;
1379 }
1380
1381 Done:
1382 CoreReleaseMemoryLock ();
1383 return Status;
1384 }
1385
1386 /**
1387 Frees previous allocated pages.
1388
1389 @param Memory Base address of memory being freed
1390 @param NumberOfPages The number of pages to free
1391
1392 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1393 @retval EFI_INVALID_PARAMETER Address not aligned
1394 @return EFI_SUCCESS -Pages successfully freed.
1395
1396 **/
1397 EFI_STATUS
1398 EFIAPI
1399 CoreFreePages (
1400 IN EFI_PHYSICAL_ADDRESS Memory,
1401 IN UINTN NumberOfPages
1402 )
1403 {
1404 EFI_STATUS Status;
1405
1406 Status = CoreInternalFreePages (Memory, NumberOfPages);
1407 if (!EFI_ERROR (Status)) {
1408 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, (EFI_MEMORY_TYPE) 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory);
1409 }
1410 return Status;
1411 }
1412
1413 /**
1414 This function checks to see if the last memory map descriptor in a memory map
1415 can be merged with any of the other memory map descriptors in a memorymap.
1416 Memory descriptors may be merged if they are adjacent and have the same type
1417 and attributes.
1418
1419 @param MemoryMap A pointer to the start of the memory map.
1420 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1421 @param DescriptorSize The size, in bytes, of an individual
1422 EFI_MEMORY_DESCRIPTOR.
1423
1424 @return A pointer to the next available descriptor in MemoryMap
1425
1426 **/
1427 EFI_MEMORY_DESCRIPTOR *
1428 MergeMemoryMapDescriptor (
1429 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
1430 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
1431 IN UINTN DescriptorSize
1432 )
1433 {
1434 //
1435 // Traverse the array of descriptors in MemoryMap
1436 //
1437 for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1438 //
1439 // Check to see if the Type fields are identical.
1440 //
1441 if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1442 continue;
1443 }
1444
1445 //
1446 // Check to see if the Attribute fields are identical.
1447 //
1448 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1449 continue;
1450 }
1451
1452 //
1453 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1454 //
1455 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1456 //
1457 // Merge MemoryMapDescriptor into MemoryMap
1458 //
1459 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1460
1461 //
1462 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1463 //
1464 return MemoryMapDescriptor;
1465 }
1466
1467 //
1468 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1469 //
1470 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1471 //
1472 // Merge MemoryMapDescriptor into MemoryMap
1473 //
1474 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
1475 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
1476 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1477
1478 //
1479 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1480 //
1481 return MemoryMapDescriptor;
1482 }
1483 }
1484
1485 //
1486 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1487 //
1488 // Return the slot immediately after MemoryMapDescriptor as the next available
1489 // slot in the MemoryMap array
1490 //
1491 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1492 }
1493
1494 /**
1495 This function returns a copy of the current memory map. The map is an array of
1496 memory descriptors, each of which describes a contiguous block of memory.
1497
1498 @param MemoryMapSize A pointer to the size, in bytes, of the
1499 MemoryMap buffer. On input, this is the size of
1500 the buffer allocated by the caller. On output,
1501 it is the size of the buffer returned by the
1502 firmware if the buffer was large enough, or the
1503 size of the buffer needed to contain the map if
1504 the buffer was too small.
1505 @param MemoryMap A pointer to the buffer in which firmware places
1506 the current memory map.
1507 @param MapKey A pointer to the location in which firmware
1508 returns the key for the current memory map.
1509 @param DescriptorSize A pointer to the location in which firmware
1510 returns the size, in bytes, of an individual
1511 EFI_MEMORY_DESCRIPTOR.
1512 @param DescriptorVersion A pointer to the location in which firmware
1513 returns the version number associated with the
1514 EFI_MEMORY_DESCRIPTOR.
1515
1516 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1517 buffer.
1518 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1519 buffer size needed to hold the memory map is
1520 returned in MemoryMapSize.
1521 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1522
1523 **/
1524 EFI_STATUS
1525 EFIAPI
1526 CoreGetMemoryMap (
1527 IN OUT UINTN *MemoryMapSize,
1528 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1529 OUT UINTN *MapKey,
1530 OUT UINTN *DescriptorSize,
1531 OUT UINT32 *DescriptorVersion
1532 )
1533 {
1534 EFI_STATUS Status;
1535 UINTN Size;
1536 UINTN BufferSize;
1537 UINTN NumberOfEntries;
1538 LIST_ENTRY *Link;
1539 MEMORY_MAP *Entry;
1540 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1541 EFI_MEMORY_TYPE Type;
1542 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1543
1544 //
1545 // Make sure the parameters are valid
1546 //
1547 if (MemoryMapSize == NULL) {
1548 return EFI_INVALID_PARAMETER;
1549 }
1550
1551 CoreAcquireGcdMemoryLock ();
1552
1553 //
1554 // Count the number of Reserved and runtime MMIO entries
1555 // And, count the number of Persistent entries.
1556 //
1557 NumberOfEntries = 0;
1558 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1559 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1560 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) ||
1561 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1562 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1563 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1564 NumberOfEntries ++;
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 * NumberOfEntries;
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 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1657 //
1658 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1659 //
1660 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
1661 MemoryMap->VirtualStart = 0;
1662 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
1663 MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;
1664
1665 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {
1666 MemoryMap->Type = EfiReservedMemoryType;
1667 } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1668 if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1669 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1670 } else {
1671 MemoryMap->Type = EfiMemoryMappedIO;
1672 }
1673 }
1674
1675 //
1676 // Check to see if the new Memory Map Descriptor can be merged with an
1677 // existing descriptor if they are adjacent and have the same attributes
1678 //
1679 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1680 }
1681
1682 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {
1683 //
1684 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1685 //
1686 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
1687 MemoryMap->VirtualStart = 0;
1688 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
1689 MemoryMap->Attribute = GcdMapEntry->Attributes | EFI_MEMORY_NV;
1690 MemoryMap->Type = EfiPersistentMemory;
1691
1692 //
1693 // Check to see if the new Memory Map Descriptor can be merged with an
1694 // existing descriptor if they are adjacent and have the same attributes
1695 //
1696 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1697 }
1698 }
1699
1700 //
1701 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1702 //
1703 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1704
1705 Status = EFI_SUCCESS;
1706
1707 Done:
1708 //
1709 // Update the map key finally
1710 //
1711 if (MapKey != NULL) {
1712 *MapKey = mMemoryMapKey;
1713 }
1714
1715 CoreReleaseMemoryLock ();
1716
1717 CoreReleaseGcdMemoryLock ();
1718
1719 *MemoryMapSize = BufferSize;
1720
1721 return Status;
1722 }
1723
1724
1725 /**
1726 Internal function. Used by the pool functions to allocate pages
1727 to back pool allocation requests.
1728
1729 @param PoolType The type of memory for the new pool pages
1730 @param NumberOfPages No of pages to allocate
1731 @param Alignment Bits to align.
1732
1733 @return The allocated memory, or NULL
1734
1735 **/
1736 VOID *
1737 CoreAllocatePoolPages (
1738 IN EFI_MEMORY_TYPE PoolType,
1739 IN UINTN NumberOfPages,
1740 IN UINTN Alignment
1741 )
1742 {
1743 UINT64 Start;
1744
1745 //
1746 // Find the pages to convert
1747 //
1748 Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
1749
1750 //
1751 // Convert it to boot services data
1752 //
1753 if (Start == 0) {
1754 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1755 } else {
1756 CoreConvertPages (Start, NumberOfPages, PoolType);
1757 }
1758
1759 return (VOID *)(UINTN) Start;
1760 }
1761
1762
1763 /**
1764 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1765
1766 @param Memory The base address to free
1767 @param NumberOfPages The number of pages to free
1768
1769 **/
1770 VOID
1771 CoreFreePoolPages (
1772 IN EFI_PHYSICAL_ADDRESS Memory,
1773 IN UINTN NumberOfPages
1774 )
1775 {
1776 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1777 }
1778
1779
1780
1781 /**
1782 Make sure the memory map is following all the construction rules,
1783 it is the last time to check memory map error before exit boot services.
1784
1785 @param MapKey Memory map key
1786
1787 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1788 rules.
1789 @retval EFI_SUCCESS Valid memory map.
1790
1791 **/
1792 EFI_STATUS
1793 CoreTerminateMemoryMap (
1794 IN UINTN MapKey
1795 )
1796 {
1797 EFI_STATUS Status;
1798 LIST_ENTRY *Link;
1799 MEMORY_MAP *Entry;
1800
1801 Status = EFI_SUCCESS;
1802
1803 CoreAcquireMemoryLock ();
1804
1805 if (MapKey == mMemoryMapKey) {
1806
1807 //
1808 // Make sure the memory map is following all the construction rules
1809 // This is the last chance we will be able to display any messages on
1810 // the console devices.
1811 //
1812
1813 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1814 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1815 if (Entry->Type < EfiMaxMemoryType) {
1816 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
1817 ASSERT (Entry->Type != EfiACPIReclaimMemory);
1818 ASSERT (Entry->Type != EfiACPIMemoryNVS);
1819 if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1820 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1821 Status = EFI_INVALID_PARAMETER;
1822 goto Done;
1823 }
1824 if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1825 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1826 Status = EFI_INVALID_PARAMETER;
1827 goto Done;
1828 }
1829 }
1830 }
1831 }
1832
1833 //
1834 // The map key they gave us matches what we expect. Fall through and
1835 // return success. In an ideal world we would clear out all of
1836 // EfiBootServicesCode and EfiBootServicesData. However this function
1837 // is not the last one called by ExitBootServices(), so we have to
1838 // preserve the memory contents.
1839 //
1840 } else {
1841 Status = EFI_INVALID_PARAMETER;
1842 }
1843
1844 Done:
1845 CoreReleaseMemoryLock ();
1846
1847 return Status;
1848 }
1849
1850
1851
1852
1853
1854
1855
1856
1857