]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
Don't align image address for TeImage, because TeImage section alignment is undefined.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
1 /** @file
2 UEFI Memory page management functions.
3
4 Copyright (c) 2007 - 2008, Intel Corporation. <BR>
5 All rights reserved. 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
17 #define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)
18
19 //
20 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
21 //
22 typedef struct {
23 EFI_PHYSICAL_ADDRESS BaseAddress;
24 EFI_PHYSICAL_ADDRESS MaximumAddress;
25 UINT64 CurrentNumberOfPages;
26 UINT64 NumberOfPages;
27 UINTN InformationIndex;
28 BOOLEAN Special;
29 BOOLEAN Runtime;
30 } EFI_MEMORY_TYPE_STAISTICS;
31
32 //
33 // MemoryMap - The current memory map
34 //
35 UINTN mMemoryMapKey = 0;
36
37 //
38 // mMapStack - space to use as temp storage to build new map descriptors
39 // mMapDepth - depth of new descriptor stack
40 //
41
42 #define MAX_MAP_DEPTH 6
43 UINTN mMapDepth = 0;
44 MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
45 UINTN mFreeMapStack = 0;
46 //
47 // This list maintain the free memory map list
48 //
49 LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
50 BOOLEAN mMemoryTypeInformationInitialized = FALSE;
51
52 EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {
53 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType
54 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode
55 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData
56 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode
57 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData
58 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode
59 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData
60 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory
61 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory
62 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory
63 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS
64 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO
65 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace
66 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode
67 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType
68 };
69
70 EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;
71
72 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
73 { EfiReservedMemoryType, 0 },
74 { EfiLoaderCode, 0 },
75 { EfiLoaderData, 0 },
76 { EfiBootServicesCode, 0 },
77 { EfiBootServicesData, 0 },
78 { EfiRuntimeServicesCode, 0 },
79 { EfiRuntimeServicesData, 0 },
80 { EfiConventionalMemory, 0 },
81 { EfiUnusableMemory, 0 },
82 { EfiACPIReclaimMemory, 0 },
83 { EfiACPIMemoryNVS, 0 },
84 { EfiMemoryMappedIO, 0 },
85 { EfiMemoryMappedIOPortSpace, 0 },
86 { EfiPalCode, 0 },
87 { EfiMaxMemoryType, 0 }
88 };
89
90
91 /**
92 Enter critical section by gaining lock on gMemoryLock.
93
94 **/
95 VOID
96 CoreAcquireMemoryLock (
97 VOID
98 )
99 {
100 CoreAcquireLock (&gMemoryLock);
101 }
102
103
104
105 /**
106 Exit critical section by releasing lock on gMemoryLock.
107
108 **/
109 VOID
110 CoreReleaseMemoryLock (
111 VOID
112 )
113 {
114 CoreReleaseLock (&gMemoryLock);
115 }
116
117
118
119
120 /**
121 Internal function. Removes a descriptor entry.
122
123 @param Entry The entry to remove
124
125 **/
126 VOID
127 RemoveMemoryMapEntry (
128 IN OUT MEMORY_MAP *Entry
129 )
130 {
131 RemoveEntryList (&Entry->Link);
132 Entry->Link.ForwardLink = NULL;
133
134 if (Entry->FromPages) {
135 //
136 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList
137 //
138 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
139 }
140 }
141
142 /**
143 Internal function. Adds a ranges to the memory map.
144 The range must not already exist in the map.
145
146 @param Type The type of memory range to add
147 @param Start The starting address in the memory range Must be
148 paged aligned
149 @param End The last address in the range Must be the last
150 byte of a page
151 @param Attribute The attributes of the memory range to add
152
153 **/
154 VOID
155 CoreAddRange (
156 IN EFI_MEMORY_TYPE Type,
157 IN EFI_PHYSICAL_ADDRESS Start,
158 IN EFI_PHYSICAL_ADDRESS End,
159 IN UINT64 Attribute
160 )
161 {
162 LIST_ENTRY *Link;
163 MEMORY_MAP *Entry;
164
165 ASSERT ((Start & EFI_PAGE_MASK) == 0);
166 ASSERT (End > Start) ;
167
168 ASSERT_LOCKED (&gMemoryLock);
169
170 DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));
171
172 //
173 // Memory map being altered so updated key
174 //
175 mMemoryMapKey += 1;
176
177 //
178 // UEFI 2.0 added an event group for notificaiton on memory map changes.
179 // So we need to signal this Event Group every time the memory map changes.
180 // If we are in EFI 1.10 compatability mode no event groups will be
181 // found and nothing will happen we we call this function. These events
182 // will get signaled but since a lock is held around the call to this
183 // function the notificaiton events will only be called after this funciton
184 // returns and the lock is released.
185 //
186 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);
187
188 //
189 // Look for adjoining memory descriptor
190 //
191
192 // Two memory descriptors can only be merged if they have the same Type
193 // and the same Attribute
194 //
195
196 Link = gMemoryMap.ForwardLink;
197 while (Link != &gMemoryMap) {
198 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
199 Link = Link->ForwardLink;
200
201 if (Entry->Type != Type) {
202 continue;
203 }
204
205 if (Entry->Attribute != Attribute) {
206 continue;
207 }
208
209 if (Entry->End + 1 == Start) {
210
211 Start = Entry->Start;
212 RemoveMemoryMapEntry (Entry);
213
214 } else if (Entry->Start == End + 1) {
215
216 End = Entry->End;
217 RemoveMemoryMapEntry (Entry);
218 }
219 }
220
221 //
222 // Add descriptor
223 //
224
225 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
226 mMapStack[mMapDepth].FromPages = FALSE;
227 mMapStack[mMapDepth].Type = Type;
228 mMapStack[mMapDepth].Start = Start;
229 mMapStack[mMapDepth].End = End;
230 mMapStack[mMapDepth].VirtualStart = 0;
231 mMapStack[mMapDepth].Attribute = Attribute;
232 InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);
233
234 mMapDepth += 1;
235 ASSERT (mMapDepth < MAX_MAP_DEPTH);
236
237 return ;
238 }
239
240 /**
241 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
242 If the list is emtry, then allocate a new page to refuel the list.
243 Please Note this algorithm to allocate the memory map descriptor has a property
244 that the memory allocated for memory entries always grows, and will never really be freed
245 For example, if the current boot uses 2000 memory map entries at the maximum point, but
246 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950
247 memory map entries is still allocated from EfiBootServicesMemory.
248
249
250 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
251
252 **/
253 MEMORY_MAP *
254 AllocateMemoryMapEntry (
255 VOID
256 )
257 {
258 MEMORY_MAP* FreeDescriptorEntries;
259 MEMORY_MAP* Entry;
260 UINTN Index;
261
262 if (IsListEmpty (&mFreeMemoryMapEntryList)) {
263 //
264 // The list is empty, to allocate one page to refuel the list
265 //
266 FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);
267 if(FreeDescriptorEntries != NULL) {
268 //
269 // Enque the free memmory map entries into the list
270 //
271 for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {
272 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
273 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
274 }
275 } else {
276 return NULL;
277 }
278 }
279 //
280 // dequeue the first descriptor from the list
281 //
282 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
283 RemoveEntryList (&Entry->Link);
284
285 return Entry;
286 }
287
288
289 /**
290 Internal function. Moves any memory descriptors that are on the
291 temporary descriptor stack to heap.
292
293 **/
294 VOID
295 CoreFreeMemoryMapStack (
296 VOID
297 )
298 {
299 MEMORY_MAP *Entry;
300 MEMORY_MAP *Entry2;
301 LIST_ENTRY *Link2;
302
303 ASSERT_LOCKED (&gMemoryLock);
304
305 //
306 // If already freeing the map stack, then return
307 //
308 if (mFreeMapStack != 0) {
309 return ;
310 }
311
312 //
313 // Move the temporary memory descriptor stack into pool
314 //
315 mFreeMapStack += 1;
316
317 while (mMapDepth != 0) {
318 //
319 // Deque an memory map entry from mFreeMemoryMapEntryList
320 //
321 Entry = AllocateMemoryMapEntry ();
322
323 ASSERT (Entry);
324
325 //
326 // Update to proper entry
327 //
328 mMapDepth -= 1;
329
330 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
331
332 //
333 // Move this entry to general memory
334 //
335 RemoveEntryList (&mMapStack[mMapDepth].Link);
336 mMapStack[mMapDepth].Link.ForwardLink = NULL;
337
338 CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
339 Entry->FromPages = TRUE;
340
341 //
342 // Find insertion location
343 //
344 for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {
345 Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
346 if (Entry2->FromPages && Entry2->Start > Entry->Start) {
347 break;
348 }
349 }
350
351 InsertTailList (Link2, &Entry->Link);
352
353 } else {
354 //
355 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,
356 // so here no need to move it to memory.
357 //
358 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
359 }
360 }
361
362 mFreeMapStack -= 1;
363 }
364
365 /**
366 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
367
368 **/
369 VOID
370 PromoteMemoryResource (
371 VOID
372 )
373 {
374 LIST_ENTRY *Link;
375 EFI_GCD_MAP_ENTRY *Entry;
376
377 DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));
378
379 CoreAcquireGcdMemoryLock ();
380
381 Link = mGcdMemorySpaceMap.ForwardLink;
382 while (Link != &mGcdMemorySpaceMap) {
383
384 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
385
386 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&
387 Entry->EndAddress < EFI_MAX_ADDRESS &&
388 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
389 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {
390 //
391 // Update the GCD map
392 //
393 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
394 Entry->Capabilities |= EFI_MEMORY_TESTED;
395 Entry->ImageHandle = gDxeCoreImageHandle;
396 Entry->DeviceHandle = NULL;
397
398 //
399 // Add to allocable system memory resource
400 //
401
402 CoreAddRange (
403 EfiConventionalMemory,
404 Entry->BaseAddress,
405 Entry->EndAddress,
406 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
407 );
408 CoreFreeMemoryMapStack ();
409
410 }
411
412 Link = Link->ForwardLink;
413 }
414
415 CoreReleaseGcdMemoryLock ();
416
417 return;
418 }
419
420
421 /**
422 Called to initialize the memory map and add descriptors to
423 the current descriptor list.
424 The first descriptor that is added must be general usable
425 memory as the addition allocates heap.
426
427 @param Type The type of memory to add
428 @param Start The starting address in the memory range Must be
429 page aligned
430 @param NumberOfPages The number of pages in the range
431 @param Attribute Attributes of the memory to add
432
433 @return None. The range is added to the memory map
434
435 **/
436 VOID
437 CoreAddMemoryDescriptor (
438 IN EFI_MEMORY_TYPE Type,
439 IN EFI_PHYSICAL_ADDRESS Start,
440 IN UINT64 NumberOfPages,
441 IN UINT64 Attribute
442 )
443 {
444 EFI_PHYSICAL_ADDRESS End;
445 EFI_STATUS Status;
446 UINTN Index;
447 UINTN FreeIndex;
448
449 if ((Start & EFI_PAGE_MASK) != 0) {
450 return;
451 }
452
453 if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {
454 return;
455 }
456
457 CoreAcquireMemoryLock ();
458 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
459 CoreAddRange (Type, Start, End, Attribute);
460 CoreFreeMemoryMapStack ();
461 CoreReleaseMemoryLock ();
462
463 //
464 // Check to see if the statistics for the different memory types have already been established
465 //
466 if (mMemoryTypeInformationInitialized) {
467 return;
468 }
469
470 //
471 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
472 //
473 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
474 //
475 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
476 //
477 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
478 if (Type < 0 || Type > EfiMaxMemoryType) {
479 continue;
480 }
481
482 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
483 //
484 // Allocate pages for the current memory type from the top of available memory
485 //
486 Status = CoreAllocatePages (
487 AllocateAnyPages,
488 Type,
489 gMemoryTypeInformation[Index].NumberOfPages,
490 &mMemoryTypeStatistics[Type].BaseAddress
491 );
492 if (EFI_ERROR (Status)) {
493 //
494 // If an error occurs allocating the pages for the current memory type, then
495 // free all the pages allocates for the previous memory types and return. This
496 // operation with be retied when/if more memory is added to the system
497 //
498 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {
499 //
500 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
501 //
502 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);
503 if (Type < 0 || Type > EfiMaxMemoryType) {
504 continue;
505 }
506
507 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {
508 CoreFreePages (
509 mMemoryTypeStatistics[Type].BaseAddress,
510 gMemoryTypeInformation[FreeIndex].NumberOfPages
511 );
512 mMemoryTypeStatistics[Type].BaseAddress = 0;
513 mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;
514 }
515 }
516 return;
517 }
518
519 //
520 // Compute the address at the top of the current statistics
521 //
522 mMemoryTypeStatistics[Type].MaximumAddress =
523 mMemoryTypeStatistics[Type].BaseAddress +
524 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;
525
526 //
527 // If the current base address is the lowest address so far, then update the default
528 // maximum address
529 //
530 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {
531 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;
532 }
533 }
534 }
535
536 //
537 // There was enough system memory for all the the memory types were allocated. So,
538 // those memory areas can be freed for future allocations, and all future memory
539 // allocations can occur within their respective bins
540 //
541 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
542 //
543 // Make sure the memory type in the gMemoryTypeInformation[] array is valid
544 //
545 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);
546 if (Type < 0 || Type > EfiMaxMemoryType) {
547 continue;
548 }
549
550 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
551 CoreFreePages (
552 mMemoryTypeStatistics[Type].BaseAddress,
553 gMemoryTypeInformation[Index].NumberOfPages
554 );
555 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;
556 gMemoryTypeInformation[Index].NumberOfPages = 0;
557 }
558 }
559
560 //
561 // If the number of pages reserved for a memory type is 0, then all allocations for that type
562 // should be in the default range.
563 //
564 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
565 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
566 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {
567 mMemoryTypeStatistics[Type].InformationIndex = Index;
568 }
569 }
570 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;
571 if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {
572 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;
573 }
574 }
575
576 mMemoryTypeInformationInitialized = TRUE;
577 }
578
579
580 /**
581 Internal function. Converts a memory range to the specified type.
582 The range must exist in the memory map.
583
584 @param Start The first address of the range Must be page
585 aligned
586 @param NumberOfPages The number of pages to convert
587 @param NewType The new type for the memory range
588
589 @retval EFI_INVALID_PARAMETER Invalid parameter
590 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified
591 range or convertion not allowed.
592 @retval EFI_SUCCESS Successfully converts the memory range to the
593 specified type.
594
595 **/
596 EFI_STATUS
597 CoreConvertPages (
598 IN UINT64 Start,
599 IN UINT64 NumberOfPages,
600 IN EFI_MEMORY_TYPE NewType
601 )
602 {
603
604 UINT64 NumberOfBytes;
605 UINT64 End;
606 UINT64 RangeEnd;
607 UINT64 Attribute;
608 LIST_ENTRY *Link;
609 MEMORY_MAP *Entry;
610
611 Entry = NULL;
612 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
613 End = Start + NumberOfBytes - 1;
614
615 ASSERT (NumberOfPages);
616 ASSERT ((Start & EFI_PAGE_MASK) == 0);
617 ASSERT (End > Start) ;
618 ASSERT_LOCKED (&gMemoryLock);
619
620 if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) {
621 return EFI_INVALID_PARAMETER;
622 }
623
624 //
625 // Convert the entire range
626 //
627
628 while (Start < End) {
629
630 //
631 // Find the entry that the covers the range
632 //
633 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
634 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
635
636 if (Entry->Start <= Start && Entry->End > Start) {
637 break;
638 }
639 }
640
641 if (Link == &gMemoryMap) {
642 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));
643 return EFI_NOT_FOUND;
644 }
645
646 //
647 // Convert range to the end, or to the end of the descriptor
648 // if that's all we've got
649 //
650 RangeEnd = End;
651 if (Entry->End < End) {
652 RangeEnd = Entry->End;
653 }
654
655 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));
656
657 //
658 // Debug code - verify conversion is allowed
659 //
660 if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {
661 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n"));
662 return EFI_NOT_FOUND;
663 }
664
665 //
666 // Update counters for the number of pages allocated to each memory type
667 //
668 if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {
669 if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress &&
670 Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {
671 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {
672 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;
673 } else {
674 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;
675 }
676 }
677 }
678
679 if (NewType >= 0 && NewType < EfiMaxMemoryType) {
680 if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {
681 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;
682 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages >
683 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {
684 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;
685 }
686 }
687 }
688
689 //
690 // Pull range out of descriptor
691 //
692 if (Entry->Start == Start) {
693
694 //
695 // Clip start
696 //
697 Entry->Start = RangeEnd + 1;
698
699 } else if (Entry->End == RangeEnd) {
700
701 //
702 // Clip end
703 //
704 Entry->End = Start - 1;
705
706 } else {
707
708 //
709 // Pull it out of the center, clip current
710 //
711
712 //
713 // Add a new one
714 //
715 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;
716 mMapStack[mMapDepth].FromPages = FALSE;
717 mMapStack[mMapDepth].Type = Entry->Type;
718 mMapStack[mMapDepth].Start = RangeEnd+1;
719 mMapStack[mMapDepth].End = Entry->End;
720
721 //
722 // Inherit Attribute from the Memory Descriptor that is being clipped
723 //
724 mMapStack[mMapDepth].Attribute = Entry->Attribute;
725
726 Entry->End = Start - 1;
727 ASSERT (Entry->Start < Entry->End);
728
729 Entry = &mMapStack[mMapDepth];
730 InsertTailList (&gMemoryMap, &Entry->Link);
731
732 mMapDepth += 1;
733 ASSERT (mMapDepth < MAX_MAP_DEPTH);
734 }
735
736 //
737 // The new range inherits the same Attribute as the Entry
738 //it is being cut out of
739 //
740 Attribute = Entry->Attribute;
741
742 //
743 // If the descriptor is empty, then remove it from the map
744 //
745 if (Entry->Start == Entry->End + 1) {
746 RemoveMemoryMapEntry (Entry);
747 Entry = NULL;
748 }
749
750 //
751 // Add our new range in
752 //
753 CoreAddRange (NewType, Start, RangeEnd, Attribute);
754
755 //
756 // Move any map descriptor stack to general pool
757 //
758 CoreFreeMemoryMapStack ();
759
760 //
761 // Bump the starting address, and convert the next range
762 //
763 Start = RangeEnd + 1;
764 }
765
766 //
767 // Converted the whole range, done
768 //
769
770 return EFI_SUCCESS;
771 }
772
773
774
775 /**
776 Internal function. Finds a consecutive free page range below
777 the requested address.
778
779 @param MaxAddress The address that the range must be below
780 @param NumberOfPages Number of pages needed
781 @param NewType The type of memory the range is going to be
782 turned into
783 @param Alignment Bits to align with
784
785 @return The base address of the range, or 0 if the range was not found
786
787 **/
788 UINT64
789 CoreFindFreePagesI (
790 IN UINT64 MaxAddress,
791 IN UINT64 NumberOfPages,
792 IN EFI_MEMORY_TYPE NewType,
793 IN UINTN Alignment
794 )
795 {
796 UINT64 NumberOfBytes;
797 UINT64 Target;
798 UINT64 DescStart;
799 UINT64 DescEnd;
800 UINT64 DescNumberOfBytes;
801 LIST_ENTRY *Link;
802 MEMORY_MAP *Entry;
803
804 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {
805 return 0;
806 }
807
808 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
809
810 //
811 // If MaxAddress is not aligned to the end of a page
812 //
813
814 //
815 // Change MaxAddress to be 1 page lower
816 //
817 MaxAddress -= (EFI_PAGE_MASK + 1);
818
819 //
820 // Set MaxAddress to a page boundary
821 //
822 MaxAddress &= ~EFI_PAGE_MASK;
823
824 //
825 // Set MaxAddress to end of the page
826 //
827 MaxAddress |= EFI_PAGE_MASK;
828 }
829
830 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);
831 Target = 0;
832
833 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
834 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
835
836 //
837 // If it's not a free entry, don't bother with it
838 //
839 if (Entry->Type != EfiConventionalMemory) {
840 continue;
841 }
842
843 DescStart = Entry->Start;
844 DescEnd = Entry->End;
845
846 //
847 // If desc is past max allowed address, skip it
848 //
849 if (DescStart >= MaxAddress) {
850 continue;
851 }
852
853 //
854 // If desc ends past max allowed address, clip the end
855 //
856 if (DescEnd >= MaxAddress) {
857 DescEnd = MaxAddress;
858 }
859
860 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;
861
862 //
863 // Compute the number of bytes we can used from this
864 // descriptor, and see it's enough to satisfy the request
865 //
866 DescNumberOfBytes = DescEnd - DescStart + 1;
867
868 if (DescNumberOfBytes >= NumberOfBytes) {
869
870 //
871 // If this is the best match so far remember it
872 //
873 if (DescEnd > Target) {
874 Target = DescEnd;
875 }
876 }
877 }
878
879 //
880 // If this is a grow down, adjust target to be the allocation base
881 //
882 Target -= NumberOfBytes - 1;
883
884 //
885 // If we didn't find a match, return 0
886 //
887 if ((Target & EFI_PAGE_MASK) != 0) {
888 return 0;
889 }
890
891 return Target;
892 }
893
894
895 /**
896 Internal function. Finds a consecutive free page range below
897 the requested address
898
899 @param MaxAddress The address that the range must be below
900 @param NoPages Number of pages needed
901 @param NewType The type of memory the range is going to be
902 turned into
903 @param Alignment Bits to align with
904
905 @return The base address of the range, or 0 if the range was not found.
906
907 **/
908 UINT64
909 FindFreePages (
910 IN UINT64 MaxAddress,
911 IN UINT64 NoPages,
912 IN EFI_MEMORY_TYPE NewType,
913 IN UINTN Alignment
914 )
915 {
916 UINT64 NewMaxAddress;
917 UINT64 Start;
918
919 NewMaxAddress = MaxAddress;
920
921 if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {
922 NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress;
923 } else {
924 if (NewMaxAddress > mDefaultMaximumAddress) {
925 NewMaxAddress = mDefaultMaximumAddress;
926 }
927 }
928
929 Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);
930 if (Start == 0) {
931 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
932 if (Start == 0) {
933 //
934 // Here means there may be no enough memory to use, so try to go through
935 // all the memory descript to promote the untested memory directly
936 //
937 PromoteMemoryResource ();
938
939 //
940 // Allocate memory again after the memory resource re-arranged
941 //
942 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);
943 }
944 }
945
946 return Start;
947 }
948
949
950
951 /**
952 Allocates pages from the memory map.
953
954 @param Type The type of allocation to perform
955 @param MemoryType The type of memory to turn the allocated pages
956 into
957 @param NumberOfPages The number of pages to allocate
958 @param Memory A pointer to receive the base allocated memory
959 address
960
961 @return Status. On success, Memory is filled in with the base address allocated
962 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in
963 spec.
964 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
965 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
966 @retval EFI_SUCCESS Pages successfully allocated.
967
968 **/
969 EFI_STATUS
970 EFIAPI
971 CoreAllocatePages (
972 IN EFI_ALLOCATE_TYPE Type,
973 IN EFI_MEMORY_TYPE MemoryType,
974 IN UINTN NumberOfPages,
975 IN OUT EFI_PHYSICAL_ADDRESS *Memory
976 )
977 {
978 EFI_STATUS Status;
979 UINT64 Start;
980 UINT64 MaxAddress;
981 UINTN Alignment;
982
983 if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) {
984 return EFI_INVALID_PARAMETER;
985 }
986
987 if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||
988 MemoryType == EfiConventionalMemory) {
989 return EFI_INVALID_PARAMETER;
990 }
991
992 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
993
994 if (MemoryType == EfiACPIReclaimMemory ||
995 MemoryType == EfiACPIMemoryNVS ||
996 MemoryType == EfiRuntimeServicesCode ||
997 MemoryType == EfiRuntimeServicesData) {
998
999 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1000 }
1001
1002 if (Type == AllocateAddress) {
1003 if ((*Memory & (Alignment - 1)) != 0) {
1004 return EFI_NOT_FOUND;
1005 }
1006 }
1007
1008 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1009 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1010
1011 //
1012 // If this is for below a particular address, then
1013 //
1014 Start = *Memory;
1015
1016 //
1017 // The max address is the max natively addressable address for the processor
1018 //
1019 MaxAddress = EFI_MAX_ADDRESS;
1020
1021 if (Type == AllocateMaxAddress) {
1022 MaxAddress = Start;
1023 }
1024
1025 CoreAcquireMemoryLock ();
1026
1027 //
1028 // If not a specific address, then find an address to allocate
1029 //
1030 if (Type != AllocateAddress) {
1031 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);
1032 if (Start == 0) {
1033 Status = EFI_OUT_OF_RESOURCES;
1034 goto Done;
1035 }
1036 }
1037
1038 //
1039 // Convert pages from FreeMemory to the requested type
1040 //
1041 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);
1042
1043 Done:
1044 CoreReleaseMemoryLock ();
1045
1046 if (!EFI_ERROR (Status)) {
1047 *Memory = Start;
1048 }
1049
1050 return Status;
1051 }
1052
1053
1054 /**
1055 Frees previous allocated pages.
1056
1057 @param Memory Base address of memory being freed
1058 @param NumberOfPages The number of pages to free
1059
1060 @retval EFI_NOT_FOUND Could not find the entry that covers the range
1061 @retval EFI_INVALID_PARAMETER Address not aligned
1062 @return EFI_SUCCESS -Pages successfully freed.
1063
1064 **/
1065 EFI_STATUS
1066 EFIAPI
1067 CoreFreePages (
1068 IN EFI_PHYSICAL_ADDRESS Memory,
1069 IN UINTN NumberOfPages
1070 )
1071 {
1072 EFI_STATUS Status;
1073 LIST_ENTRY *Link;
1074 MEMORY_MAP *Entry;
1075 UINTN Alignment;
1076
1077 //
1078 // Free the range
1079 //
1080 CoreAcquireMemoryLock ();
1081
1082 //
1083 // Find the entry that the covers the range
1084 //
1085 Entry = NULL;
1086 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1087 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1088 if (Entry->Start <= Memory && Entry->End > Memory) {
1089 break;
1090 }
1091 }
1092 if (Link == &gMemoryMap) {
1093 CoreReleaseMemoryLock ();
1094 return EFI_NOT_FOUND;
1095 }
1096
1097 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;
1098
1099 if (Entry->Type == EfiACPIReclaimMemory ||
1100 Entry->Type == EfiACPIMemoryNVS ||
1101 Entry->Type == EfiRuntimeServicesCode ||
1102 Entry->Type == EfiRuntimeServicesData) {
1103
1104 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
1105
1106 }
1107
1108 if ((Memory & (Alignment - 1)) != 0) {
1109 CoreReleaseMemoryLock ();
1110 return EFI_INVALID_PARAMETER;
1111 }
1112
1113 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;
1114 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);
1115
1116 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1117
1118 CoreReleaseMemoryLock ();
1119
1120 if (EFI_ERROR (Status)) {
1121 return Status;
1122 }
1123
1124 //
1125 // Destroy the contents
1126 //
1127 if (Memory < EFI_MAX_ADDRESS) {
1128 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);
1129 }
1130
1131 return Status;
1132 }
1133
1134
1135 /**
1136 This function returns a copy of the current memory map. The map is an array of
1137 memory descriptors, each of which describes a contiguous block of memory.
1138
1139 @param MemoryMapSize A pointer to the size, in bytes, of the
1140 MemoryMap buffer. On input, this is the size of
1141 the buffer allocated by the caller. On output,
1142 it is the size of the buffer returned by the
1143 firmware if the buffer was large enough, or the
1144 size of the buffer needed to contain the map if
1145 the buffer was too small.
1146 @param MemoryMap A pointer to the buffer in which firmware places
1147 the current memory map.
1148 @param MapKey A pointer to the location in which firmware
1149 returns the key for the current memory map.
1150 @param DescriptorSize A pointer to the location in which firmware
1151 returns the size, in bytes, of an individual
1152 EFI_MEMORY_DESCRIPTOR.
1153 @param DescriptorVersion A pointer to the location in which firmware
1154 returns the version number associated with the
1155 EFI_MEMORY_DESCRIPTOR.
1156
1157 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1158 buffer.
1159 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1160 buffer size needed to hold the memory map is
1161 returned in MemoryMapSize.
1162 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1163
1164 **/
1165 EFI_STATUS
1166 EFIAPI
1167 CoreGetMemoryMap (
1168 IN OUT UINTN *MemoryMapSize,
1169 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1170 OUT UINTN *MapKey,
1171 OUT UINTN *DescriptorSize,
1172 OUT UINT32 *DescriptorVersion
1173 )
1174 {
1175 EFI_STATUS Status;
1176 UINTN Size;
1177 UINTN BufferSize;
1178 UINTN NumberOfRuntimeEntries;
1179 LIST_ENTRY *Link;
1180 MEMORY_MAP *Entry;
1181 EFI_GCD_MAP_ENTRY *GcdMapEntry;
1182 EFI_MEMORY_TYPE Type;
1183
1184 //
1185 // Make sure the parameters are valid
1186 //
1187 if (MemoryMapSize == NULL) {
1188 return EFI_INVALID_PARAMETER;
1189 }
1190
1191 CoreAcquireGcdMemoryLock ();
1192
1193 //
1194 // Count the number of Reserved and MMIO entries that are marked for runtime use
1195 //
1196 NumberOfRuntimeEntries = 0;
1197 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1198 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1199 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1200 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
1201 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
1202 NumberOfRuntimeEntries++;
1203 }
1204 }
1205 }
1206
1207 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1208
1209 //
1210 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1211 // prevent people from having pointer math bugs in their code.
1212 // now you have to use *DescriptorSize to make things work.
1213 //
1214 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1215
1216 if (DescriptorSize != NULL) {
1217 *DescriptorSize = Size;
1218 }
1219
1220 if (DescriptorVersion != NULL) {
1221 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1222 }
1223
1224 CoreAcquireMemoryLock ();
1225
1226 //
1227 // Compute the buffer size needed to fit the entire map
1228 //
1229 BufferSize = Size * NumberOfRuntimeEntries;
1230 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1231 BufferSize += Size;
1232 }
1233
1234 if (*MemoryMapSize < BufferSize) {
1235 Status = EFI_BUFFER_TOO_SMALL;
1236 goto Done;
1237 }
1238
1239 if (MemoryMap == NULL) {
1240 Status = EFI_INVALID_PARAMETER;
1241 goto Done;
1242 }
1243
1244 //
1245 // Build the map
1246 //
1247 ZeroMem (MemoryMap, BufferSize);
1248 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1249 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1250 ASSERT (Entry->VirtualStart == 0);
1251
1252 //
1253 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1254 //
1255 MemoryMap->Type = Entry->Type;
1256 MemoryMap->PhysicalStart = Entry->Start;
1257 MemoryMap->VirtualStart = Entry->VirtualStart;
1258 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1259 //
1260 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1261 // memory type bin and needs to be converted to the same memory type as the rest of the
1262 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1263 // improves the chances for a successful S4 resume in the presence of minor page allocation
1264 // differences across reboots.
1265 //
1266 if (MemoryMap->Type == EfiConventionalMemory) {
1267 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1268 if (mMemoryTypeStatistics[Type].Special &&
1269 mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
1270 Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
1271 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
1272 MemoryMap->Type = Type;
1273 }
1274 }
1275 }
1276 MemoryMap->Attribute = Entry->Attribute;
1277 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1278 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1279 }
1280
1281 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
1282 }
1283
1284 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1285 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1286 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1287 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {
1288 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
1289
1290 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;
1291 MemoryMap->VirtualStart = 0;
1292 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);
1293 MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;
1294
1295 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {
1296 MemoryMap->Type = EfiReservedMemoryType;
1297 } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1298 if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1299 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1300 } else {
1301 MemoryMap->Type = EfiMemoryMappedIO;
1302 }
1303 }
1304
1305 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);
1306 }
1307 }
1308 }
1309
1310 Status = EFI_SUCCESS;
1311
1312 Done:
1313
1314 CoreReleaseMemoryLock ();
1315
1316 CoreReleaseGcdMemoryLock ();
1317
1318 //
1319 // Update the map key finally
1320 //
1321 if (MapKey != NULL) {
1322 *MapKey = mMemoryMapKey;
1323 }
1324
1325 *MemoryMapSize = BufferSize;
1326
1327 return Status;
1328 }
1329
1330
1331 /**
1332 Internal function. Used by the pool functions to allocate pages
1333 to back pool allocation requests.
1334
1335 @param PoolType The type of memory for the new pool pages
1336 @param NumberOfPages No of pages to allocate
1337 @param Alignment Bits to align.
1338
1339 @return The allocated memory, or NULL
1340
1341 **/
1342 VOID *
1343 CoreAllocatePoolPages (
1344 IN EFI_MEMORY_TYPE PoolType,
1345 IN UINTN NumberOfPages,
1346 IN UINTN Alignment
1347 )
1348 {
1349 UINT64 Start;
1350
1351 //
1352 // Find the pages to convert
1353 //
1354 Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
1355
1356 //
1357 // Convert it to boot services data
1358 //
1359 if (Start == 0) {
1360 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));
1361 } else {
1362 CoreConvertPages (Start, NumberOfPages, PoolType);
1363 }
1364
1365 return (VOID *)(UINTN) Start;
1366 }
1367
1368
1369 /**
1370 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1371
1372 @param Memory The base address to free
1373 @param NumberOfPages The number of pages to free
1374
1375 **/
1376 VOID
1377 CoreFreePoolPages (
1378 IN EFI_PHYSICAL_ADDRESS Memory,
1379 IN UINTN NumberOfPages
1380 )
1381 {
1382 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1383 }
1384
1385
1386
1387 /**
1388 Make sure the memory map is following all the construction rules,
1389 it is the last time to check memory map error before exit boot services.
1390
1391 @param MapKey Memory map key
1392
1393 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1394 rules.
1395 @retval EFI_SUCCESS Valid memory map.
1396
1397 **/
1398 EFI_STATUS
1399 CoreTerminateMemoryMap (
1400 IN UINTN MapKey
1401 )
1402 {
1403 EFI_STATUS Status;
1404 LIST_ENTRY *Link;
1405 MEMORY_MAP *Entry;
1406
1407 Status = EFI_SUCCESS;
1408
1409 CoreAcquireMemoryLock ();
1410
1411 if (MapKey == mMemoryMapKey) {
1412
1413 //
1414 // Make sure the memory map is following all the construction rules
1415 // This is the last chance we will be able to display any messages on
1416 // the console devices.
1417 //
1418
1419 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1420 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1421 if (Entry->Attribute & EFI_MEMORY_RUNTIME) {
1422 if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {
1423 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));
1424 Status = EFI_INVALID_PARAMETER;
1425 goto Done;
1426 }
1427 if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
1428 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1429 Status = EFI_INVALID_PARAMETER;
1430 goto Done;
1431 }
1432 if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {
1433 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1434 Status = EFI_INVALID_PARAMETER;
1435 goto Done;
1436 }
1437 }
1438 }
1439
1440 //
1441 // The map key they gave us matches what we expect. Fall through and
1442 // return success. In an ideal world we would clear out all of
1443 // EfiBootServicesCode and EfiBootServicesData. However this function
1444 // is not the last one called by ExitBootServices(), so we have to
1445 // preserve the memory contents.
1446 //
1447 } else {
1448 Status = EFI_INVALID_PARAMETER;
1449 }
1450
1451 Done:
1452 CoreReleaseMemoryLock ();
1453
1454 return Status;
1455 }
1456
1457
1458
1459
1460
1461
1462
1463
1464