1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/mm/mm.c 5 * PURPOSE: Boot Library Memory Manager Core 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bl.h" 12 #include "bcd.h" 13 14 /* DATA VARIABLES ************************************************************/ 15 16 /* This is a bug in Windows, but is required for MmTrInitialize to load */ 17 BL_TRANSLATION_TYPE MmTranslationType = BlMax; 18 BL_TRANSLATION_TYPE MmOriginalTranslationType; 19 ULONG MmDescriptorCallTreeCount; 20 21 /* FUNCTIONS *****************************************************************/ 22 23 NTSTATUS 24 TrpGenerateMappingTracker ( 25 _In_ PVOID VirtualAddress, 26 _In_ ULONG Flags, 27 _In_ LARGE_INTEGER PhysicalAddress, 28 _In_ ULONGLONG Size 29 ) 30 { 31 PBL_MEMORY_DESCRIPTOR Descriptor, NextDescriptor; 32 PLIST_ENTRY ListHead, NextEntry; 33 34 /* Increment descriptor call count */ 35 MmDescriptorCallTreeCount++; 36 37 /* Initialize a descriptor for this allocation */ 38 Descriptor = MmMdInitByteGranularDescriptor(Flags, 39 0, 40 PhysicalAddress.QuadPart, 41 (ULONG_PTR)VirtualAddress, 42 Size); 43 44 /* Loop the current tracker list */ 45 ListHead = MmMdlMappingTrackers.First; 46 NextEntry = ListHead->Flink; 47 if (IsListEmpty(ListHead)) 48 { 49 /* If it's empty, just add the descriptor at the end */ 50 InsertTailList(ListHead, &Descriptor->ListEntry); 51 goto Quickie; 52 } 53 54 /* Otherwise, go to the last descriptor */ 55 NextDescriptor = CONTAINING_RECORD(NextEntry, 56 BL_MEMORY_DESCRIPTOR, 57 ListEntry); 58 while (NextDescriptor->VirtualPage < Descriptor->VirtualPage) 59 { 60 /* Keep going... */ 61 NextEntry = NextEntry->Flink; 62 NextDescriptor = CONTAINING_RECORD(NextEntry, 63 BL_MEMORY_DESCRIPTOR, 64 ListEntry); 65 66 /* If we hit the end of the list, just add it at the end */ 67 if (NextEntry == ListHead) 68 { 69 goto Quickie; 70 } 71 72 /* Otherwise, add it right after this descriptor */ 73 InsertTailList(&NextDescriptor->ListEntry, &Descriptor->ListEntry); 74 } 75 76 Quickie: 77 /* Release any global descriptors allocated */ 78 MmMdFreeGlobalDescriptors(); 79 --MmDescriptorCallTreeCount; 80 return STATUS_SUCCESS; 81 } 82 83 NTSTATUS 84 MmTrInitialize ( 85 VOID 86 ) 87 { 88 PBL_MEMORY_DESCRIPTOR Descriptor; 89 NTSTATUS Status; 90 PLIST_ENTRY NextEntry; 91 92 /* Nothing to track if we're using physical memory */ 93 if (MmTranslationType == BlNone) 94 { 95 return STATUS_SUCCESS; 96 } 97 98 /* Initialize all the virtual lists */ 99 MmMdInitializeListHead(&MmMdlMappingTrackers); 100 MmMdlMappingTrackers.Type = BlMdTracker; 101 MmMdInitializeListHead(&MmMdlFreeVirtual); 102 MmMdlFreeVirtual.Type = BlMdVirtual; 103 104 /* Initialize a 4GB free descriptor */ 105 Descriptor = MmMdInitByteGranularDescriptor(0, 106 BlConventionalMemory, 107 0, 108 0, 109 ((ULONGLONG)4 * 1024 * 1024 * 1024) >> 110 PAGE_SHIFT); 111 if (!Descriptor) 112 { 113 Status = STATUS_NO_MEMORY; 114 goto Quickie; 115 } 116 117 /* Add this 4GB region to the free virtual address space list */ 118 Status = MmMdAddDescriptorToList(&MmMdlFreeVirtual, 119 Descriptor, 120 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG); 121 if (!NT_SUCCESS(Status)) 122 { 123 RtlZeroMemory(Descriptor, sizeof(*Descriptor)); 124 goto Quickie; 125 } 126 127 /* Remove any reserved regions of virtual address space */ 128 NextEntry = MmMdlReservedAllocated.First->Flink; 129 while (NextEntry != MmMdlReservedAllocated.First) 130 { 131 /* Grab the descriptor and see if it's mapped */ 132 Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); 133 if (Descriptor->VirtualPage) 134 { 135 EfiPrintf(L"Need to handle reserved allocation: %llx %llx\r\n", 136 Descriptor->VirtualPage, Descriptor->PageCount); 137 EfiStall(100000); 138 Status = STATUS_NOT_IMPLEMENTED; 139 goto Quickie; 140 } 141 142 /* Next entry */ 143 NextEntry = NextEntry->Flink; 144 } 145 146 /* Set success if we made it */ 147 Status = STATUS_SUCCESS; 148 149 Quickie: 150 /* Return back to caller */ 151 return Status; 152 } 153 154 NTSTATUS 155 BlMmRemoveBadMemory ( 156 VOID 157 ) 158 { 159 BOOLEAN AllowBad; 160 NTSTATUS Status; 161 PULONGLONG BadPages; 162 ULONGLONG BadPageCount; 163 164 /* First check if bad memory access is allowed */ 165 AllowBad = FALSE; 166 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 167 BcdLibraryBoolean_AllowBadMemoryAccess, 168 &AllowBad); 169 if ((NT_SUCCESS(Status)) && (AllowBad)) 170 { 171 /* No point checking the list if it is */ 172 return STATUS_SUCCESS; 173 } 174 175 /* Otherwise, check if there's a persisted bad page list */ 176 Status = BlpGetBootOptionIntegerList(BlpApplicationEntry.BcdData, 177 BcdLibraryIntegerList_BadMemoryList, 178 &BadPages, 179 &BadPageCount, 180 TRUE); 181 if (NT_SUCCESS(Status)) 182 { 183 EfiPrintf(L"Persistent bad page list not supported\r\n"); 184 return STATUS_NOT_IMPLEMENTED; 185 } 186 187 /* All done here */ 188 return STATUS_SUCCESS; 189 } 190 191 NTSTATUS 192 BlMmMapPhysicalAddressEx ( 193 _In_ PVOID* VirtualAddress, 194 _In_ ULONG Flags, 195 _In_ ULONGLONG Size, 196 _In_ PHYSICAL_ADDRESS PhysicalAddress 197 ) 198 { 199 NTSTATUS Status; 200 PVOID MappingAddress; 201 PHYSICAL_ADDRESS MappedAddress; 202 PVOID MappedBase; 203 ULONGLONG MapSize; 204 UCHAR CacheAttributes; 205 ULONGLONG BasePage, EndPage, MappedPage, FoundBasePage; 206 ULONGLONG PageOffset, FoundPageCount; 207 PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor; 208 PBL_MEMORY_DESCRIPTOR_LIST List; 209 ULONG AddPages; 210 211 /* Increase call depth */ 212 ++MmDescriptorCallTreeCount; 213 214 /* Check if any parameters are missing */ 215 if (!(VirtualAddress) || !(Size)) 216 { 217 Status = STATUS_INVALID_PARAMETER; 218 goto Quickie; 219 } 220 221 /* Check for fixed allocation without an actual address */ 222 if ((Flags & BlMemoryFixed) && 223 (PhysicalAddress.QuadPart == -1) && 224 !(*VirtualAddress)) 225 { 226 Status = STATUS_INVALID_PARAMETER; 227 goto Quickie; 228 } 229 230 /* Check for invalid requirement flag, if one is present */ 231 if (((Flags & BlMemoryValidAllocationAttributes) != BlMemoryFixed) && 232 ((Flags & BlMemoryValidAllocationAttributes) != BlMemoryKernelRange) && 233 (Flags & BlMemoryValidAllocationAttributes)) 234 { 235 Status = STATUS_INVALID_PARAMETER; 236 goto Quickie; 237 } 238 239 /* Check for invalid cache attribute flags */ 240 if (((Flags & BlMemoryValidCacheAttributeMask) - 1) & 241 (Flags & BlMemoryValidCacheAttributeMask)) 242 { 243 Status = STATUS_INVALID_PARAMETER; 244 goto Quickie; 245 } 246 247 /* Select an address to map this at */ 248 Status = MmSelectMappingAddress(&MappingAddress, 249 *VirtualAddress, 250 Size, 251 Flags & BlMemoryValidAllocationAttributes, 252 Flags, 253 PhysicalAddress); 254 if (!NT_SUCCESS(Status)) 255 { 256 goto Quickie; 257 } 258 259 /* Map the selected address, using the appropriate caching attributes */ 260 MappedAddress = PhysicalAddress; 261 MapSize = Size; 262 CacheAttributes = ((Flags & BlMemoryValidCacheAttributeMask) != 0x20) ? 263 (Flags & BlMemoryValidCacheAttributeMask) : 0; 264 Status = MmMapPhysicalAddress(&MappedAddress, 265 &MappingAddress, 266 &MapSize, 267 CacheAttributes); 268 if (!NT_SUCCESS(Status)) 269 { 270 goto Quickie; 271 } 272 273 /* Compute the final address where the mapping was made */ 274 MappedBase = (PVOID)(ULONG_PTR)((ULONG_PTR)MappingAddress + 275 PhysicalAddress.QuadPart - 276 MappedAddress.QuadPart); 277 MappedAddress.QuadPart = (ULONG_PTR)MappedBase; 278 279 /* Check if we're in physical or virtual mode */ 280 if (MmTranslationType == BlNone) 281 { 282 /* We are in physical mode -- just return this address directly */ 283 Status = STATUS_SUCCESS; 284 *VirtualAddress = MappedBase; 285 goto Quickie; 286 } 287 288 /* Remove the mapping address from the list of free virtual memory */ 289 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual, 290 BL_MM_REMOVE_VIRTUAL_REGION_FLAG, 291 (ULONG_PTR)MappingAddress >> PAGE_SHIFT, 292 MapSize >> PAGE_SHIFT, 293 NULL); 294 if (NT_SUCCESS(Status)) 295 { 296 /* And then add an entry for the fact we mapped it */ 297 Status = TrpGenerateMappingTracker(MappedBase, 298 CacheAttributes, 299 PhysicalAddress, 300 MapSize); 301 } 302 303 /* Abandon if we didn't update the memory map successfully */ 304 if (!NT_SUCCESS(Status)) 305 { 306 /* Unmap the virtual address so it can be used later */ 307 MmUnmapVirtualAddress(MappingAddress, &MapSize); 308 goto Quickie; 309 } 310 311 /* Check if no real mapping into RAM was made */ 312 if (PhysicalAddress.QuadPart == -1) 313 { 314 /* Then we're done here */ 315 Status = STATUS_SUCCESS; 316 *VirtualAddress = MappedBase; 317 goto Quickie; 318 } 319 320 321 /* Loop over the entire allocation */ 322 BasePage = MappedAddress.QuadPart >> PAGE_SHIFT; 323 EndPage = (MappedAddress.QuadPart + MapSize) >> PAGE_SHIFT; 324 MappedPage = (ULONG_PTR)MappingAddress >> PAGE_SHIFT; 325 do 326 { 327 /* Start with the unmapped allocated list */ 328 List = &MmMdlUnmappedAllocated; 329 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_ALLOCATED, 330 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 331 BasePage); 332 if (!Descriptor) 333 { 334 /* Try persistent next */ 335 List = &MmMdlPersistentMemory; 336 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_PERSISTENT_MEMORY, 337 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 338 BasePage); 339 } 340 if (!Descriptor) 341 { 342 /* Try unmapped, unallocated, next */ 343 List = &MmMdlUnmappedUnallocated; 344 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED, 345 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 346 BasePage); 347 } 348 if (!Descriptor) 349 { 350 /* Try reserved next */ 351 List = &MmMdlReservedAllocated; 352 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_RESERVED_ALLOCATED, 353 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 354 BasePage); 355 } 356 357 /* Check if we have a descriptor */ 358 if (Descriptor) 359 { 360 /* Remove it from its list */ 361 MmMdRemoveDescriptorFromList(List, Descriptor); 362 363 /* Check if it starts before our allocation */ 364 FoundBasePage = Descriptor->BasePage; 365 if (FoundBasePage < BasePage) 366 { 367 /* Create a new descriptor to cover the gap before our allocation */ 368 PageOffset = BasePage - FoundBasePage; 369 NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, 370 Descriptor->Type, 371 FoundBasePage, 372 0, 373 PageOffset); 374 375 /* Insert it */ 376 MmMdAddDescriptorToList(List, NewDescriptor, 0); 377 378 /* Adjust ours to ignore that piece */ 379 Descriptor->PageCount -= PageOffset; 380 Descriptor->BasePage = BasePage; 381 } 382 383 /* Check if it goes beyond our allocation */ 384 FoundPageCount = Descriptor->PageCount; 385 if (EndPage < (FoundPageCount + Descriptor->BasePage)) 386 { 387 /* Create a new descriptor to cover the range after our allocation */ 388 PageOffset = EndPage - BasePage; 389 NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, 390 Descriptor->Type, 391 EndPage, 392 0, 393 FoundPageCount - 394 PageOffset); 395 396 /* Insert it */ 397 MmMdAddDescriptorToList(List, NewDescriptor, 0); 398 399 /* Adjust ours to ignore that piece */ 400 Descriptor->PageCount = PageOffset; 401 } 402 403 /* Update the descriptor to be mapepd at this virtual page */ 404 Descriptor->VirtualPage = MappedPage; 405 406 /* Check if this was one of the regular lists */ 407 if ((List != &MmMdlReservedAllocated) && 408 (List != &MmMdlPersistentMemory)) 409 { 410 /* Was it allocated, or unallocated? */ 411 if (List != &MmMdlUnmappedAllocated) 412 { 413 /* In which case use the unallocated mapped list */ 414 List = &MmMdlMappedUnallocated; 415 } 416 else 417 { 418 /* Insert it into the mapped list */ 419 List = &MmMdlMappedAllocated; 420 } 421 } 422 423 /* Add the descriptor that was removed, into the right list */ 424 MmMdAddDescriptorToList(List, Descriptor, 0); 425 426 /* Add the pages this descriptor had */ 427 AddPages = Descriptor->PageCount; 428 } 429 else 430 { 431 /* Nope, so just add one page */ 432 AddPages = 1; 433 } 434 435 /* Increment the number of pages the descriptor had */ 436 MappedPage += AddPages; 437 BasePage += AddPages; 438 } 439 while (BasePage < EndPage); 440 441 /* We're done -- returned the address */ 442 Status = STATUS_SUCCESS; 443 *VirtualAddress = MappedBase; 444 445 Quickie: 446 /* Cleanup descriptors and reduce depth */ 447 MmMdFreeGlobalDescriptors(); 448 --MmDescriptorCallTreeCount; 449 return Status; 450 } 451 452 NTSTATUS 453 MmUnmapVirtualAddress ( 454 _Inout_ PVOID* VirtualAddress, 455 _Inout_ PULONGLONG Size 456 ) 457 { 458 NTSTATUS Status; 459 460 /* Make sure parameters were passed in and are valid */ 461 if ((VirtualAddress) && (Size) && (*Size <= 0xFFFFFFFF)) 462 { 463 /* Nothing to do if translation isn't active */ 464 if (MmTranslationType == BlNone) 465 { 466 Status = STATUS_SUCCESS; 467 } 468 else 469 { 470 /* We don't support virtual memory yet @TODO */ 471 EfiPrintf(L"unmap not yet implemented in %S\r\n", __FUNCTION__); 472 EfiStall(1000000); 473 Status = STATUS_NOT_IMPLEMENTED; 474 } 475 } 476 else 477 { 478 /* Fail */ 479 Status = STATUS_INVALID_PARAMETER; 480 } 481 482 /* All done */ 483 return Status; 484 } 485 486 NTSTATUS 487 BlMmUnmapVirtualAddressEx ( 488 _In_ PVOID VirtualAddress, 489 _In_ ULONGLONG Size 490 ) 491 { 492 NTSTATUS Status; 493 494 /* Increment call depth */ 495 ++MmDescriptorCallTreeCount; 496 497 /* Make sure all parameters are there */ 498 if ((VirtualAddress) && (Size)) 499 { 500 /* Unmap the virtual address */ 501 Status = MmUnmapVirtualAddress(&VirtualAddress, &Size); 502 503 /* Check if we actually had a virtual mapping active */ 504 if ((NT_SUCCESS(Status)) && (MmTranslationType != BlNone)) 505 { 506 /* We don't support virtual memory yet @TODO */ 507 EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__); 508 EfiStall(1000000); 509 Status = STATUS_NOT_IMPLEMENTED; 510 } 511 } 512 else 513 { 514 /* Fail */ 515 Status = STATUS_INVALID_PARAMETER; 516 } 517 518 /* Cleanup descriptors and reduce depth */ 519 MmMdFreeGlobalDescriptors(); 520 --MmDescriptorCallTreeCount; 521 return Status; 522 } 523 524 BOOLEAN 525 BlMmTranslateVirtualAddress ( 526 _In_ PVOID VirtualAddress, 527 _Out_ PPHYSICAL_ADDRESS PhysicalAddress 528 ) 529 { 530 /* Make sure arguments are present */ 531 if (!(VirtualAddress) || !(PhysicalAddress)) 532 { 533 return FALSE; 534 } 535 536 /* Do the architecture-specific translation */ 537 return MmArchTranslateVirtualAddress(VirtualAddress, PhysicalAddress, NULL); 538 } 539 540 NTSTATUS 541 BlpMmInitialize ( 542 _In_ PBL_MEMORY_DATA MemoryData, 543 _In_ BL_TRANSLATION_TYPE TranslationType, 544 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters 545 ) 546 { 547 NTSTATUS Status; 548 549 /* Take a reference */ 550 MmDescriptorCallTreeCount = 1; 551 552 /* Only support valid translation types */ 553 if ((TranslationType > BlPae) || (LibraryParameters->TranslationType > BlPae)) 554 { 555 /* Bail out */ 556 EfiPrintf(L"Invalid translation types present\r\n"); 557 Status = STATUS_INVALID_PARAMETER; 558 goto Quickie; 559 } 560 561 /* Initialize memory descriptors */ 562 MmMdInitialize(0, LibraryParameters); 563 564 /* Remember the page type we came in with */ 565 MmOriginalTranslationType = TranslationType; 566 567 /* Initialize the physical page allocator */ 568 Status = MmPaInitialize(MemoryData, 569 LibraryParameters->MinimumAllocationCount); 570 if (!NT_SUCCESS(Status)) 571 { 572 goto Quickie; 573 } 574 575 /* Initialize the memory tracker */ 576 Status = MmTrInitialize(); 577 if (!NT_SUCCESS(Status)) 578 { 579 EfiPrintf(L"TR Mm init failed: %lx\r\n", Status); 580 //MmArchDestroy(); 581 //MmPaDestroy(1); 582 goto Quickie; 583 } 584 585 /* Initialize paging, large pages, self-mapping, PAE, if needed */ 586 Status = MmArchInitialize(1, 587 MemoryData, 588 TranslationType, 589 LibraryParameters->TranslationType); 590 if (NT_SUCCESS(Status)) 591 { 592 /* Save the newly active transation type */ 593 MmTranslationType = LibraryParameters->TranslationType; 594 595 /* Initialize the heap allocator now */ 596 Status = MmHaInitialize(LibraryParameters->MinimumHeapSize, 597 LibraryParameters->HeapAllocationAttributes); 598 } 599 600 /* If Phase 1 init failed, bail out */ 601 if (!NT_SUCCESS(Status)) 602 { 603 /* Kill everything set setup so far */ 604 EfiPrintf(L"Phase 1 Mm init failed: %lx\r\n", Status); 605 //MmPaDestroy(0); 606 //MmTrDestroy(); 607 //MmArchDestroy(); 608 //MmPaDestroy(1); 609 goto Quickie; 610 } 611 612 /* Do we have too many descriptors? */ 613 if (LibraryParameters->DescriptorCount > 512) 614 { 615 /* Switch to using a dynamic buffer instead */ 616 EfiPrintf(L"Warning: too many descriptors\r\n"); 617 Status = STATUS_NOT_IMPLEMENTED; 618 goto Quickie; 619 //MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount); 620 } 621 622 /* Remove memory that the BCD says is bad */ 623 BlMmRemoveBadMemory(); 624 625 /* Now map all the memory regions as needed */ 626 Status = MmArchInitialize(2, 627 MemoryData, 628 TranslationType, 629 LibraryParameters->TranslationType); 630 if (NT_SUCCESS(Status)) 631 { 632 /* Initialize the block allocator */ 633 Status = MmBaInitialize(); 634 } 635 636 /* Check if anything in phase 2 failed */ 637 if (!NT_SUCCESS(Status)) 638 { 639 /* Go back to static descriptors and kill the heap */ 640 EfiPrintf(L"Phase 2 Mm init failed: %lx\r\n", Status); 641 //MmMdpSwitchToStaticDescriptors(); 642 //HapInitializationStatus = 0; 643 //++MmDescriptorCallTreeCount; 644 645 /* Destroy the Phase 1 initialization */ 646 //MmPaDestroy(0); 647 //MmTrDestroy(); 648 //MmArchDestroy(); 649 //MmPaDestroy(1); 650 } 651 652 Quickie: 653 /* Free the memory descriptors and return the initialization state */ 654 MmMdFreeGlobalDescriptors(); 655 --MmDescriptorCallTreeCount; 656 return Status; 657 } 658