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