]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
a28552934f6baba5d2402b241c23edfd60e3e917
[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 < MEMORY_TYPE_OEM_RESERVED_MIN) {
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 // Skip if DescEnd is less than DescStart after alignment clipping
1055 if (DescEnd < DescStart) {
1056 continue;
1057 }
1058
1059 //
1060 // Compute the number of bytes we can used from this
1061 // descriptor, and see it's enough to satisfy the request
1062 //
1063 DescNumberOfBytes = DescEnd - DescStart + 1;
1064
1065 if (DescNumberOfBytes >= NumberOfBytes) {
1066 //
1067 // If the start of the allocated range is below the min address allowed, skip it
1068 //
1069 if ((DescEnd - NumberOfBytes + 1) < MinAddress) {
1070 continue;
1071 }
1072
1073 //
1074 // If this is the best match so far remember it
1075 //
1076 if (DescEnd > Target) {
1077 Target = DescEnd;
1078 }
1079 }
1080 }
1081
1082 //
1083 // If this is a grow down, adjust target to be the allocation base
1084 //
1085 Target -= NumberOfBytes - 1;
1086
1087 //
1088 // If we didn't find a match, return 0
1089 //
1090 if ((Target & EFI_PAGE_MASK) != 0) {
1091 return 0;
1092 }
1093
1094 return Target;
1095 }
1096
1097
1098 /**
1099 Internal function. Finds a consecutive free page range below
1100 the requested address
1101
1102 @param MaxAddress The address that the range must be below
1103 @param NoPages Number of pages needed
1104 @param NewType The type of memory the range is going to be
1105 turned into
1106 @param Alignment Bits to align with
1107
1108 @return The base address of the range, or 0 if the range was not found.
1109
1110 **/
1111 UINT64
1112 FindFreePages (
1113 IN UINT64 MaxAddress,
1114 IN UINT64 NoPages,
1115 IN EFI_MEMORY_TYPE NewType,
1116 IN UINTN Alignment
1117 )
1118 {
1119 UINT64 Start;
1120
1121 //
1122 // Attempt to find free pages in the preferred bin based on the requested memory type
1123 //
1124 if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
1125 Start = CoreFindFreePagesI (
1126 mMemoryTypeStatistics[NewType].MaximumAddress,
1127 mMemoryTypeStatistics[NewType].BaseAddress,
1128 NoPages,
1129 NewType,
1130 Alignment
1131 );
1132 if (Start != 0) {
1133 return Start;
1134 }
1135 }
1136
1137 //
1138 // Attempt to find free pages in the default allocation bin
1139 //
1140 if (MaxAddress >= mDefaultMaximumAddress) {
1141 Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, Alignment);
1142 if (Start != 0) {
1143 if (Start < mDefaultBaseAddress) {
1144 mDefaultBaseAddress = Start;
1145 }
1146 return Start;
1147 }
1148 }
1149
1150 //
1151 // The allocation did not succeed in any of the prefered bins even after
1152 // promoting resources. Attempt to find free pages anywhere is the requested
1153 // address range. If this allocation fails, then there are not enough
1154 // resources anywhere to satisfy the request.
1155 //
1156 Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment);
1157 if (Start != 0) {
1158 return Start;
1159 }
1160
1161 //
1162 // If allocations from the preferred bins fail, then attempt to promote memory resources.
1163 //
1164 if (!PromoteMemoryResource ()) {
1165 return 0;
1166 }
1167
1168 //
1169 // If any memory resources were promoted, then re-attempt the allocation
1170 //
1171 return FindFreePages (MaxAddress, NoPages, NewType, Alignment);
1172 }
1173
1174
1175 /**
1176 Allocates pages from the memory map.
1177
1178 @param Type The type of allocation to perform
1179 @param MemoryType The type of memory to turn the allocated pages
1180 into
1181 @param NumberOfPages The number of pages to allocate
1182 @param Memory A pointer to receive the base allocated memory
1183 address
1184
1185 @return Status. On success, Memory is filled in with the base address allocated
1186 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1187 spec.
1188 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1189 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1190 @retval EFI_SUCCESS Pages successfully allocated.
1191
1192 **/
1193 EFI_STATUS
1194 EFIAPI
1195 CoreInternalAllocatePages (
1196 IN EFI_ALLOCATE_TYPE Type,
1197 IN EFI_MEMORY_TYPE MemoryType,
1198 IN UINTN NumberOfPages,
1199 IN OUT EFI_PHYSICAL_ADDRESS *Memory
1200 )
1201 {
1202 EFI_STATUS Status;
1203 UINT64 Start;
1204 UINT64 MaxAddress;
1205 UINTN Alignment;
1206
1207 if ((UINT32)Type >= MaxAllocateType) {
1208 return EFI_INVALID_PARAMETER;
1209 }
1210
1211 if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
1212 (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
1213 return EFI_INVALID_PARAMETER;
1214 }
1215
1216 if (Memory == NULL) {
1217 return EFI_INVALID_PARAMETER;
1218 }
1219
1220 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1221
1222 if (MemoryType == EfiACPIReclaimMemory ||
1223 MemoryType == EfiACPIMemoryNVS ||
1224 MemoryType == EfiRuntimeServicesCode ||
1225 MemoryType == EfiRuntimeServicesData) {
1226
1227 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1228 }
1229
1230 if (Type == AllocateAddress) {
1231 if ((*Memory & (Alignment - 1)) != 0) {
1232 return EFI_NOT_FOUND;
1233 }
1234 }
1235
1236 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1237 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1238
1239 //
1240 // If this is for below a particular address, then
1241 //
1242 Start = *Memory;
1243
1244 //
1245 // The max address is the max natively addressable address for the processor
1246 //
1247 MaxAddress = MAX_ADDRESS;
1248
1249 if (Type == AllocateMaxAddress) {
1250 MaxAddress = Start;
1251 }
1252
1253 CoreAcquireMemoryLock ();
1254
1255 //
1256 // If not a specific address, then find an address to allocate
1257 //
1258 if (Type != AllocateAddress) {
1259 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
1260 if (Start == 0) {
1261 Status = EFI_OUT_OF_RESOURCES;
1262 goto Done;
1263 }
1264 }
1265
1266 //
1267 // Convert pages from FreeMemory to the requested type
1268 //
1269 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
1270
1271 Done:
1272 CoreReleaseMemoryLock ();
1273
1274 if (!EFI_ERROR (Status)) {
1275 *Memory = Start;
1276 }
1277
1278 return Status;
1279 }
1280
1281 /**
1282 Allocates pages from the memory map.
1283
1284 @param Type The type of allocation to perform
1285 @param MemoryType The type of memory to turn the allocated pages
1286 into
1287 @param NumberOfPages The number of pages to allocate
1288 @param Memory A pointer to receive the base allocated memory
1289 address
1290
1291 @return Status. On success, Memory is filled in with the base address allocated
1292 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
1293 spec.
1294 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
1295 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
1296 @retval EFI_SUCCESS Pages successfully allocated.
1297
1298 **/
1299 EFI_STATUS
1300 EFIAPI
1301 CoreAllocatePages (
1302 IN EFI_ALLOCATE_TYPE Type,
1303 IN EFI_MEMORY_TYPE MemoryType,
1304 IN UINTN NumberOfPages,
1305 OUT EFI_PHYSICAL_ADDRESS *Memory
1306 )
1307 {
1308 EFI_STATUS Status;
1309
1310 Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
1311 if (!EFI_ERROR (Status)) {
1312 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages, MemoryType, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) *Memory);
1313 }
1314 return Status;
1315 }
1316
1317 /**
1318 Frees previous allocated pages.
1319
1320 @param Memory Base address of memory being freed
1321 @param NumberOfPages The number of pages to free
1322
1323 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1324 @retval EFI_INVALID_PARAMETER Address not aligned
1325 @return EFI_SUCCESS -Pages successfully freed.
1326
1327 **/
1328 EFI_STATUS
1329 EFIAPI
1330 CoreInternalFreePages (
1331 IN EFI_PHYSICAL_ADDRESS Memory,
1332 IN UINTN NumberOfPages
1333 )
1334 {
1335 EFI_STATUS Status;
1336 LIST_ENTRY *Link;
1337 MEMORY_MAP *Entry;
1338 UINTN Alignment;
1339
1340 //
1341 // Free the range
1342 //
1343 CoreAcquireMemoryLock ();
1344
1345 //
1346 // Find the entry that the covers the range
1347 //
1348 Entry = NULL;
1349 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1350 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1351 if (Entry->Start <= Memory && Entry->End > Memory) {
1352 break;
1353 }
1354 }
1355 if (Link == &gMemoryMap) {
1356 Status = EFI_NOT_FOUND;
1357 goto Done;
1358 }
1359
1360 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1361
1362 ASSERT (Entry != NULL);
1363 if (Entry->Type == EfiACPIReclaimMemory ||
1364 Entry->Type == EfiACPIMemoryNVS ||
1365 Entry->Type == EfiRuntimeServicesCode ||
1366 Entry->Type == EfiRuntimeServicesData) {
1367
1368 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1369
1370 }
1371
1372 if ((Memory & (Alignment - 1)) != 0) {
1373 Status = EFI_INVALID_PARAMETER;
1374 goto Done;
1375 }
1376
1377 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1378 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1379
1380 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1381
1382 if (EFI_ERROR (Status)) {
1383 goto Done;
1384 }
1385
1386 Done:
1387 CoreReleaseMemoryLock ();
1388 return Status;
1389 }
1390
1391 /**
1392 Frees previous allocated pages.
1393
1394 @param Memory Base address of memory being freed
1395 @param NumberOfPages The number of pages to free
1396
1397 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1398 @retval EFI_INVALID_PARAMETER Address not aligned
1399 @return EFI_SUCCESS -Pages successfully freed.
1400
1401 **/
1402 EFI_STATUS
1403 EFIAPI
1404 CoreFreePages (
1405 IN EFI_PHYSICAL_ADDRESS Memory,
1406 IN UINTN NumberOfPages
1407 )
1408 {
1409 EFI_STATUS Status;
1410
1411 Status = CoreInternalFreePages (Memory, NumberOfPages);
1412 if (!EFI_ERROR (Status)) {
1413 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePages, (EFI_MEMORY_TYPE) 0, EFI_PAGES_TO_SIZE (NumberOfPages), (VOID *) (UINTN) Memory);
1414 }
1415 return Status;
1416 }
1417
1418 /**
1419 This function checks to see if the last memory map descriptor in a memory map
1420 can be merged with any of the other memory map descriptors in a memorymap.
1421 Memory descriptors may be merged if they are adjacent and have the same type
1422 and attributes.
1423
1424 @param MemoryMap A pointer to the start of the memory map.
1425 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.
1426 @param DescriptorSize The size, in bytes, of an individual
1427 EFI_MEMORY_DESCRIPTOR.
1428
1429 @return A pointer to the next available descriptor in MemoryMap
1430
1431 **/
1432 EFI_MEMORY_DESCRIPTOR *
1433 MergeMemoryMapDescriptor (
1434 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
1435 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,
1436 IN UINTN DescriptorSize
1437 )
1438 {
1439 //
1440 // Traverse the array of descriptors in MemoryMap
1441 //
1442 for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {
1443 //
1444 // Check to see if the Type fields are identical.
1445 //
1446 if (MemoryMap->Type != MemoryMapDescriptor->Type) {
1447 continue;
1448 }
1449
1450 //
1451 // Check to see if the Attribute fields are identical.
1452 //
1453 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {
1454 continue;
1455 }
1456
1457 //
1458 // Check to see if MemoryMapDescriptor is immediately above MemoryMap
1459 //
1460 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1461 //
1462 // Merge MemoryMapDescriptor into MemoryMap
1463 //
1464 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1465
1466 //
1467 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1468 //
1469 return MemoryMapDescriptor;
1470 }
1471
1472 //
1473 // Check to see if MemoryMapDescriptor is immediately below MemoryMap
1474 //
1475 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {
1476 //
1477 // Merge MemoryMapDescriptor into MemoryMap
1478 //
1479 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;
1480 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;
1481 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;
1482
1483 //
1484 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array
1485 //
1486 return MemoryMapDescriptor;
1487 }
1488 }
1489
1490 //
1491 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.
1492 //
1493 // Return the slot immediately after MemoryMapDescriptor as the next available
1494 // slot in the MemoryMap array
1495 //
1496 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);
1497 }
1498
1499 /**
1500 This function returns a copy of the current memory map. The map is an array of
1501 memory descriptors, each of which describes a contiguous block of memory.
1502
1503 @param MemoryMapSize A pointer to the size, in bytes, of the
1504 MemoryMap buffer. On input, this is the size of
1505 the buffer allocated by the caller. On output,
1506 it is the size of the buffer returned by the
1507 firmware if the buffer was large enough, or the
1508 size of the buffer needed to contain the map if
1509 the buffer was too small.
1510 @param MemoryMap A pointer to the buffer in which firmware places
1511 the current memory map.
1512 @param MapKey A pointer to the location in which firmware
1513 returns the key for the current memory map.
1514 @param DescriptorSize A pointer to the location in which firmware
1515 returns the size, in bytes, of an individual
1516 EFI_MEMORY_DESCRIPTOR.
1517 @param DescriptorVersion A pointer to the location in which firmware
1518 returns the version number associated with the
1519 EFI_MEMORY_DESCRIPTOR.
1520
1521 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1522 buffer.
1523 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1524 buffer size needed to hold the memory map is
1525 returned in MemoryMapSize.
1526 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1527
1528 **/
1529 EFI_STATUS
1530 EFIAPI
1531 CoreGetMemoryMap (
1532 IN OUT UINTN *MemoryMapSize,
1533 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1534 OUT UINTN *MapKey,
1535 OUT UINTN *DescriptorSize,
1536 OUT UINT32 *DescriptorVersion
1537 )
1538 {
1539 EFI_STATUS Status;
1540 UINTN Size;
1541 UINTN BufferSize;
1542 UINTN NumberOfEntries;
1543 LIST_ENTRY *Link;
1544 MEMORY_MAP *Entry;
1545 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1546 EFI_MEMORY_TYPE Type;
1547 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1548
1549 //
1550 // Make sure the parameters are valid
1551 //
1552 if (MemoryMapSize == NULL) {
1553 return EFI_INVALID_PARAMETER;
1554 }
1555
1556 CoreAcquireGcdMemoryLock ();
1557
1558 //
1559 // Count the number of Reserved and runtime MMIO entries
1560 // And, count the number of Persistent entries.
1561 //
1562 NumberOfEntries = 0;
1563 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1564 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1565 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) ||
1566 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1567 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1568 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1569 NumberOfEntries ++;
1570 }
1571 }
1572
1573 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1574
1575 //
1576 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1577 // prevent people from having pointer math bugs in their code.
1578 // now you have to use *DescriptorSize to make things work.
1579 //
1580 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1581
1582 if (DescriptorSize != NULL) {
1583 *DescriptorSize = Size;
1584 }
1585
1586 if (DescriptorVersion != NULL) {
1587 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1588 }
1589
1590 CoreAcquireMemoryLock ();
1591
1592 //
1593 // Compute the buffer size needed to fit the entire map
1594 //
1595 BufferSize = Size * NumberOfEntries;
1596 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1597 BufferSize += Size;
1598 }
1599
1600 if (*MemoryMapSize < BufferSize) {
1601 Status = EFI_BUFFER_TOO_SMALL;
1602 goto Done;
1603 }
1604
1605 if (MemoryMap == NULL) {
1606 Status = EFI_INVALID_PARAMETER;
1607 goto Done;
1608 }
1609
1610 //
1611 // Build the map
1612 //
1613 ZeroMem (MemoryMap, BufferSize);
1614 MemoryMapStart = MemoryMap;
1615 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1616 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1617 ASSERT (Entry->VirtualStart == 0);
1618
1619 //
1620 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1621 //
1622 MemoryMap->Type = Entry->Type;
1623 MemoryMap->PhysicalStart = Entry->Start;
1624 MemoryMap->VirtualStart = Entry->VirtualStart;
1625 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1626 //
1627 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1628 // memory type bin and needs to be converted to the same memory type as the rest of the
1629 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1630 // improves the chances for a successful S4 resume in the presence of minor page allocation
1631 // differences across reboots.
1632 //
1633 if (MemoryMap->Type == EfiConventionalMemory) {
1634 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1635 if (mMemoryTypeStatistics[Type].Special &&
1636 mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
1637 Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
1638 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
1639 MemoryMap->Type = Type;
1640 }
1641 }
1642 }
1643 MemoryMap->Attribute = Entry->Attribute;
1644 if (MemoryMap->Type < EfiMaxMemoryType) {
1645 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1646 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1647 }
1648 }
1649
1650 //
1651 // Check to see if the new Memory Map Descriptor can be merged with an
1652 // existing descriptor if they are adjacent and have the same attributes
1653 //
1654 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1655 }
1656
1657 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1658 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1659 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1660 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1661 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1662 //
1663 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1664 //
1665 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
1666 MemoryMap->VirtualStart = 0;
1667 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
1668 MemoryMap->Attribute = (GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO) |
1669 (GcdMapEntry->Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1670 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1671
1672 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {
1673 MemoryMap->Type = EfiReservedMemoryType;
1674 } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1675 if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1676 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1677 } else {
1678 MemoryMap->Type = EfiMemoryMappedIO;
1679 }
1680 }
1681
1682 //
1683 // Check to see if the new Memory Map Descriptor can be merged with an
1684 // existing descriptor if they are adjacent and have the same attributes
1685 //
1686 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1687 }
1688
1689 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {
1690 //
1691 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1692 //
1693 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
1694 MemoryMap->VirtualStart = 0;
1695 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
1696 MemoryMap->Attribute = GcdMapEntry->Attributes | EFI_MEMORY_NV |
1697 (GcdMapEntry->Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1698 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1699 MemoryMap->Type = EfiPersistentMemory;
1700
1701 //
1702 // Check to see if the new Memory Map Descriptor can be merged with an
1703 // existing descriptor if they are adjacent and have the same attributes
1704 //
1705 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1706 }
1707 }
1708
1709 //
1710 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1711 //
1712 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1713
1714 Status = EFI_SUCCESS;
1715
1716 Done:
1717 //
1718 // Update the map key finally
1719 //
1720 if (MapKey != NULL) {
1721 *MapKey = mMemoryMapKey;
1722 }
1723
1724 CoreReleaseMemoryLock ();
1725
1726 CoreReleaseGcdMemoryLock ();
1727
1728 *MemoryMapSize = BufferSize;
1729
1730 return Status;
1731 }
1732
1733
1734 /**
1735 Internal function. Used by the pool functions to allocate pages
1736 to back pool allocation requests.
1737
1738 @param PoolType The type of memory for the new pool pages
1739 @param NumberOfPages No of pages to allocate
1740 @param Alignment Bits to align.
1741
1742 @return The allocated memory, or NULL
1743
1744 **/
1745 VOID *
1746 CoreAllocatePoolPages (
1747 IN EFI_MEMORY_TYPE PoolType,
1748 IN UINTN NumberOfPages,
1749 IN UINTN Alignment
1750 )
1751 {
1752 UINT64 Start;
1753
1754 //
1755 // Find the pages to convert
1756 //
1757 Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
1758
1759 //
1760 // Convert it to boot services data
1761 //
1762 if (Start == 0) {
1763 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1764 } else {
1765 CoreConvertPages (Start, NumberOfPages, PoolType);
1766 }
1767
1768 return (VOID *)(UINTN) Start;
1769 }
1770
1771
1772 /**
1773 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1774
1775 @param Memory The base address to free
1776 @param NumberOfPages The number of pages to free
1777
1778 **/
1779 VOID
1780 CoreFreePoolPages (
1781 IN EFI_PHYSICAL_ADDRESS Memory,
1782 IN UINTN NumberOfPages
1783 )
1784 {
1785 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1786 }
1787
1788
1789
1790 /**
1791 Make sure the memory map is following all the construction rules,
1792 it is the last time to check memory map error before exit boot services.
1793
1794 @param MapKey Memory map key
1795
1796 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1797 rules.
1798 @retval EFI_SUCCESS Valid memory map.
1799
1800 **/
1801 EFI_STATUS
1802 CoreTerminateMemoryMap (
1803 IN UINTN MapKey
1804 )
1805 {
1806 EFI_STATUS Status;
1807 LIST_ENTRY *Link;
1808 MEMORY_MAP *Entry;
1809
1810 Status = EFI_SUCCESS;
1811
1812 CoreAcquireMemoryLock ();
1813
1814 if (MapKey == mMemoryMapKey) {
1815
1816 //
1817 // Make sure the memory map is following all the construction rules
1818 // This is the last chance we will be able to display any messages on
1819 // the console devices.
1820 //
1821
1822 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1823 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1824 if (Entry->Type < EfiMaxMemoryType) {
1825 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
1826 ASSERT (Entry->Type != EfiACPIReclaimMemory);
1827 ASSERT (Entry->Type != EfiACPIMemoryNVS);
1828 if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1829 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1830 Status = EFI_INVALID_PARAMETER;
1831 goto Done;
1832 }
1833 if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1834 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1835 Status = EFI_INVALID_PARAMETER;
1836 goto Done;
1837 }
1838 }
1839 }
1840 }
1841
1842 //
1843 // The map key they gave us matches what we expect. Fall through and
1844 // return success. In an ideal world we would clear out all of
1845 // EfiBootServicesCode and EfiBootServicesData. However this function
1846 // is not the last one called by ExitBootServices(), so we have to
1847 // preserve the memory contents.
1848 //
1849 } else {
1850 Status = EFI_INVALID_PARAMETER;
1851 }
1852
1853 Done:
1854 CoreReleaseMemoryLock ();
1855
1856 return Status;
1857 }
1858
1859
1860
1861
1862
1863
1864
1865
1866