]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg DxeCore: Check Start consistently in CoreConvertPagesEx
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
1 /** @file
2 UEFI Memory page management functions.
3
4 Copyright (c) 2007 - 2016, 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 >= End)) {
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_GCD_MAP_ENTRY MergeGcdMapEntry;
1547 EFI_MEMORY_TYPE Type;
1548 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
1549
1550 //
1551 // Make sure the parameters are valid
1552 //
1553 if (MemoryMapSize == NULL) {
1554 return EFI_INVALID_PARAMETER;
1555 }
1556
1557 CoreAcquireGcdMemoryLock ();
1558
1559 //
1560 // Count the number of Reserved and runtime MMIO entries
1561 // And, count the number of Persistent entries.
1562 //
1563 NumberOfEntries = 0;
1564 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {
1565 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1566 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) ||
1567 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1568 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1569 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1570 NumberOfEntries ++;
1571 }
1572 }
1573
1574 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1575
1576 //
1577 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1578 // prevent people from having pointer math bugs in their code.
1579 // now you have to use *DescriptorSize to make things work.
1580 //
1581 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1582
1583 if (DescriptorSize != NULL) {
1584 *DescriptorSize = Size;
1585 }
1586
1587 if (DescriptorVersion != NULL) {
1588 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1589 }
1590
1591 CoreAcquireMemoryLock ();
1592
1593 //
1594 // Compute the buffer size needed to fit the entire map
1595 //
1596 BufferSize = Size * NumberOfEntries;
1597 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1598 BufferSize += Size;
1599 }
1600
1601 if (*MemoryMapSize < BufferSize) {
1602 Status = EFI_BUFFER_TOO_SMALL;
1603 goto Done;
1604 }
1605
1606 if (MemoryMap == NULL) {
1607 Status = EFI_INVALID_PARAMETER;
1608 goto Done;
1609 }
1610
1611 //
1612 // Build the map
1613 //
1614 ZeroMem (MemoryMap, BufferSize);
1615 MemoryMapStart = MemoryMap;
1616 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1617 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1618 ASSERT (Entry->VirtualStart == 0);
1619
1620 //
1621 // Convert internal map into an EFI_MEMORY_DESCRIPTOR
1622 //
1623 MemoryMap->Type = Entry->Type;
1624 MemoryMap->PhysicalStart = Entry->Start;
1625 MemoryMap->VirtualStart = Entry->VirtualStart;
1626 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1627 //
1628 // If the memory type is EfiConventionalMemory, then determine if the range is part of a
1629 // memory type bin and needs to be converted to the same memory type as the rest of the
1630 // memory type bin in order to minimize EFI Memory Map changes across reboots. This
1631 // improves the chances for a successful S4 resume in the presence of minor page allocation
1632 // differences across reboots.
1633 //
1634 if (MemoryMap->Type == EfiConventionalMemory) {
1635 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {
1636 if (mMemoryTypeStatistics[Type].Special &&
1637 mMemoryTypeStatistics[Type].NumberOfPages > 0 &&
1638 Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&
1639 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {
1640 MemoryMap->Type = Type;
1641 }
1642 }
1643 }
1644 MemoryMap->Attribute = Entry->Attribute;
1645 if (MemoryMap->Type < EfiMaxMemoryType) {
1646 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {
1647 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;
1648 }
1649 }
1650
1651 //
1652 // Check to see if the new Memory Map Descriptor can be merged with an
1653 // existing descriptor if they are adjacent and have the same attributes
1654 //
1655 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1656 }
1657
1658
1659 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));
1660 GcdMapEntry = NULL;
1661 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {
1662 if (Link != &mGcdMemorySpaceMap) {
1663 //
1664 // Merge adjacent same type and attribute GCD memory range
1665 //
1666 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1667
1668 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&
1669 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&
1670 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&
1671 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) {
1672 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;
1673 continue;
1674 }
1675 }
1676
1677 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||
1678 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
1679 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {
1680 //
1681 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1682 // it will be recorded as page PhysicalStart and NumberOfPages.
1683 //
1684 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1685 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1686
1687 //
1688 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries
1689 //
1690 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1691 MemoryMap->VirtualStart = 0;
1692 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1693 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |
1694 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1695 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1696
1697 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {
1698 MemoryMap->Type = EfiReservedMemoryType;
1699 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
1700 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {
1701 MemoryMap->Type = EfiMemoryMappedIOPortSpace;
1702 } else {
1703 MemoryMap->Type = EfiMemoryMappedIO;
1704 }
1705 }
1706
1707 //
1708 // Check to see if the new Memory Map Descriptor can be merged with an
1709 // existing descriptor if they are adjacent and have the same attributes
1710 //
1711 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1712 }
1713
1714 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {
1715 //
1716 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
1717 // it will be recorded as page PhysicalStart and NumberOfPages.
1718 //
1719 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);
1720 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);
1721
1722 //
1723 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries
1724 //
1725 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;
1726 MemoryMap->VirtualStart = 0;
1727 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);
1728 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |
1729 (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO |
1730 EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB));
1731 MemoryMap->Type = EfiPersistentMemory;
1732
1733 //
1734 // Check to see if the new Memory Map Descriptor can be merged with an
1735 // existing descriptor if they are adjacent and have the same attributes
1736 //
1737 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
1738 }
1739 if (Link == &mGcdMemorySpaceMap) {
1740 //
1741 // break loop when arrive at head.
1742 //
1743 break;
1744 }
1745 if (GcdMapEntry != NULL) {
1746 //
1747 // Copy new GCD map entry for the following GCD range merge
1748 //
1749 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));
1750 }
1751 }
1752
1753 //
1754 // Compute the size of the buffer actually used after all memory map descriptor merge operations
1755 //
1756 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);
1757
1758 Status = EFI_SUCCESS;
1759
1760 Done:
1761 //
1762 // Update the map key finally
1763 //
1764 if (MapKey != NULL) {
1765 *MapKey = mMemoryMapKey;
1766 }
1767
1768 CoreReleaseMemoryLock ();
1769
1770 CoreReleaseGcdMemoryLock ();
1771
1772 *MemoryMapSize = BufferSize;
1773
1774 return Status;
1775 }
1776
1777
1778 /**
1779 Internal function. Used by the pool functions to allocate pages
1780 to back pool allocation requests.
1781
1782 @param PoolType The type of memory for the new pool pages
1783 @param NumberOfPages No of pages to allocate
1784 @param Alignment Bits to align.
1785
1786 @return The allocated memory, or NULL
1787
1788 **/
1789 VOID *
1790 CoreAllocatePoolPages (
1791 IN EFI_MEMORY_TYPE PoolType,
1792 IN UINTN NumberOfPages,
1793 IN UINTN Alignment
1794 )
1795 {
1796 UINT64 Start;
1797
1798 //
1799 // Find the pages to convert
1800 //
1801 Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);
1802
1803 //
1804 // Convert it to boot services data
1805 //
1806 if (Start == 0) {
1807 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));
1808 } else {
1809 CoreConvertPages (Start, NumberOfPages, PoolType);
1810 }
1811
1812 return (VOID *)(UINTN) Start;
1813 }
1814
1815
1816 /**
1817 Internal function. Frees pool pages allocated via AllocatePoolPages ()
1818
1819 @param Memory The base address to free
1820 @param NumberOfPages The number of pages to free
1821
1822 **/
1823 VOID
1824 CoreFreePoolPages (
1825 IN EFI_PHYSICAL_ADDRESS Memory,
1826 IN UINTN NumberOfPages
1827 )
1828 {
1829 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
1830 }
1831
1832
1833
1834 /**
1835 Make sure the memory map is following all the construction rules,
1836 it is the last time to check memory map error before exit boot services.
1837
1838 @param MapKey Memory map key
1839
1840 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction
1841 rules.
1842 @retval EFI_SUCCESS Valid memory map.
1843
1844 **/
1845 EFI_STATUS
1846 CoreTerminateMemoryMap (
1847 IN UINTN MapKey
1848 )
1849 {
1850 EFI_STATUS Status;
1851 LIST_ENTRY *Link;
1852 MEMORY_MAP *Entry;
1853
1854 Status = EFI_SUCCESS;
1855
1856 CoreAcquireMemoryLock ();
1857
1858 if (MapKey == mMemoryMapKey) {
1859
1860 //
1861 // Make sure the memory map is following all the construction rules
1862 // This is the last chance we will be able to display any messages on
1863 // the console devices.
1864 //
1865
1866 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {
1867 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1868 if (Entry->Type < EfiMaxMemoryType) {
1869 if (mMemoryTypeStatistics[Entry->Type].Runtime) {
1870 ASSERT (Entry->Type != EfiACPIReclaimMemory);
1871 ASSERT (Entry->Type != EfiACPIMemoryNVS);
1872 if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1873 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1874 Status = EFI_INVALID_PARAMETER;
1875 goto Done;
1876 }
1877 if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
1878 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));
1879 Status = EFI_INVALID_PARAMETER;
1880 goto Done;
1881 }
1882 }
1883 }
1884 }
1885
1886 //
1887 // The map key they gave us matches what we expect. Fall through and
1888 // return success. In an ideal world we would clear out all of
1889 // EfiBootServicesCode and EfiBootServicesData. However this function
1890 // is not the last one called by ExitBootServices(), so we have to
1891 // preserve the memory contents.
1892 //
1893 } else {
1894 Status = EFI_INVALID_PARAMETER;
1895 }
1896
1897 Done:
1898 CoreReleaseMemoryLock ();
1899
1900 return Status;
1901 }
1902
1903
1904
1905
1906
1907
1908
1909
1910