1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/mm/i386/mmx86.c 5 * PURPOSE: Boot Library Memory Manager x86-Specific Code 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bl.h" 12 #include "bcd.h" 13 14 #define PTE_BASE 0xC0000000 15 16 // 17 // Specific PDE/PTE macros to be used inside the boot library environment 18 // 19 #define MiAddressToPte(x) ((PMMPTE)(((((ULONG)(x)) >> 12) << 2) + (ULONG_PTR)MmPteBase)) 20 #define MiAddressToPde(x) ((PMMPDE)(((((ULONG)(x)) >> 22) << 2) + (ULONG_PTR)MmPdeBase)) 21 #define MiAddressToPteOffset(x) ((((ULONG)(x)) << 10) >> 22) 22 #define MiAddressToPdeOffset(x) (((ULONG)(x)) / (1024 * PAGE_SIZE)) 23 24 /* DATA VARIABLES ************************************************************/ 25 26 ULONG_PTR MmArchKsegBase; 27 ULONG_PTR MmArchKsegBias; 28 ULONG MmArchLargePageSize; 29 BL_ADDRESS_RANGE MmArchKsegAddressRange; 30 ULONG_PTR MmArchTopOfApplicationAddressSpace; 31 PHYSICAL_ADDRESS Mmx86SelfMapBase; 32 ULONG MmDeferredMappingCount; 33 PMMPTE MmPdpt; 34 PULONG MmArchReferencePage; 35 PVOID MmPteBase; 36 PVOID MmPdeBase; 37 ULONG MmArchReferencePageSize; 38 39 PBL_MM_TRANSLATE_VIRTUAL_ADDRESS Mmx86TranslateVirtualAddress; 40 PBL_MM_MAP_PHYSICAL_ADDRESS Mmx86MapPhysicalAddress; 41 PBL_MM_REMAP_VIRTUAL_ADDRESS Mmx86RemapVirtualAddress; 42 PBL_MM_UNMAP_VIRTUAL_ADDRESS Mmx86UnmapVirtualAddress; 43 PBL_MM_FLUSH_TLB Mmx86FlushTlb; 44 PBL_MM_FLUSH_TLB_ENTRY Mmx86FlushTlbEntry; 45 PBL_MM_DESTROY_SELF_MAP Mmx86DestroySelfMap; 46 47 PBL_MM_RELOCATE_SELF_MAP BlMmRelocateSelfMap; 48 PBL_MM_FLUSH_TLB BlMmFlushTlb; 49 PBL_MM_MOVE_VIRTUAL_ADDRESS_RANGE BlMmMoveVirtualAddressRange; 50 PBL_MM_ZERO_VIRTUAL_ADDRESS_RANGE BlMmZeroVirtualAddressRange; 51 52 PBL_MM_FLUSH_TLB Mmx86FlushTlb; 53 54 /* FUNCTIONS *****************************************************************/ 55 56 BOOLEAN 57 BlMmIsTranslationEnabled ( 58 VOID 59 ) 60 { 61 /* Return if paging is on */ 62 return ((CurrentExecutionContext) && 63 (CurrentExecutionContext->ContextFlags & BL_CONTEXT_PAGING_ON)); 64 } 65 66 VOID 67 MmArchNullFunction ( 68 VOID 69 ) 70 { 71 /* Nothing to do */ 72 return; 73 } 74 75 VOID 76 MmDefRelocateSelfMap ( 77 VOID 78 ) 79 { 80 if (MmPteBase != (PVOID)PTE_BASE) 81 { 82 EfiPrintf(L"Supposed to relocate CR3\r\n"); 83 } 84 } 85 86 NTSTATUS 87 MmDefMoveVirtualAddressRange ( 88 _In_ PVOID DestinationAddress, 89 _In_ PVOID SourceAddress, 90 _In_ ULONGLONG Size 91 ) 92 { 93 EfiPrintf(L"Supposed to move shit\r\n"); 94 return STATUS_NOT_IMPLEMENTED; 95 } 96 97 NTSTATUS 98 MmDefZeroVirtualAddressRange ( 99 _In_ PVOID DestinationAddress, 100 _In_ ULONGLONG Size 101 ) 102 { 103 EfiPrintf(L"Supposed to zero shit\r\n"); 104 return STATUS_NOT_IMPLEMENTED; 105 } 106 107 BOOLEAN 108 MmArchTranslateVirtualAddress ( 109 _In_ PVOID VirtualAddress, 110 _Out_opt_ PPHYSICAL_ADDRESS PhysicalAddress, 111 _Out_opt_ PULONG CachingFlags 112 ) 113 { 114 PBL_MEMORY_DESCRIPTOR Descriptor; 115 116 /* Check if paging is on */ 117 if ((CurrentExecutionContext) && 118 (CurrentExecutionContext->ContextFlags & BL_CONTEXT_PAGING_ON)) 119 { 120 /* Yes -- we have to translate this from virtual */ 121 return Mmx86TranslateVirtualAddress(VirtualAddress, 122 PhysicalAddress, 123 CachingFlags); 124 } 125 126 /* Look in all descriptors except truncated and firmware ones */ 127 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_NO_FIRMWARE_MEMORY & 128 ~BL_MM_INCLUDE_TRUNCATED_MEMORY, 129 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 130 (ULONG_PTR)VirtualAddress >> PAGE_SHIFT); 131 132 /* Return the virtual address as the physical address */ 133 if (PhysicalAddress) 134 { 135 PhysicalAddress->HighPart = 0; 136 PhysicalAddress->LowPart = (ULONG_PTR)VirtualAddress; 137 } 138 139 /* There's no caching on physical memory */ 140 if (CachingFlags) 141 { 142 *CachingFlags = 0; 143 } 144 145 /* Success is if we found a descriptor */ 146 return Descriptor != NULL; 147 } 148 149 VOID 150 MmDefpDestroySelfMap ( 151 VOID 152 ) 153 { 154 EfiPrintf(L"No destroy\r\n"); 155 } 156 157 VOID 158 MmDefpFlushTlbEntry ( 159 _In_ PVOID VirtualAddress 160 ) 161 { 162 /* Flush the TLB */ 163 __invlpg(VirtualAddress); 164 } 165 166 VOID 167 MmDefpFlushTlb ( 168 VOID 169 ) 170 { 171 /* Flush the TLB */ 172 __writecr3(__readcr3()); 173 } 174 175 NTSTATUS 176 MmDefpUnmapVirtualAddress ( 177 _In_ PVOID VirtualAddress, 178 _In_ ULONG Size 179 ) 180 { 181 EfiPrintf(L"No unmap\r\n"); 182 return STATUS_NOT_IMPLEMENTED; 183 } 184 185 NTSTATUS 186 MmDefpRemapVirtualAddress ( 187 _In_ PPHYSICAL_ADDRESS PhysicalAddress, 188 _Out_ PVOID VirtualAddress, 189 _In_ ULONG Size, 190 _In_ ULONG CacheAttributes 191 ) 192 { 193 EfiPrintf(L"No remap\r\n"); 194 return STATUS_NOT_IMPLEMENTED; 195 } 196 197 NTSTATUS 198 MmDefpMapPhysicalAddress ( 199 _In_ PHYSICAL_ADDRESS PhysicalAddress, 200 _In_ PVOID VirtualAddress, 201 _In_ ULONG Size, 202 _In_ ULONG CacheAttributes 203 ) 204 { 205 BOOLEAN Enabled; 206 ULONG i, PageCount, PdeOffset; 207 ULONGLONG CurrentAddress; 208 PMMPDE Pde; 209 PMMPTE Pte; 210 PMMPTE PageTable; 211 PHYSICAL_ADDRESS PageTableAddress; 212 NTSTATUS Status; 213 214 /* Check if paging is on yet */ 215 Enabled = BlMmIsTranslationEnabled(); 216 217 /* Get the physical address aligned */ 218 CurrentAddress = (PhysicalAddress.QuadPart >> PAGE_SHIFT) << PAGE_SHIFT; 219 220 /* Get the number of pages and loop through each one */ 221 PageCount = Size >> PAGE_SHIFT; 222 for (i = 0; i < PageCount; i++) 223 { 224 /* Check if translation already exists for this page */ 225 if (Mmx86TranslateVirtualAddress(VirtualAddress, NULL, NULL)) 226 { 227 /* Ignore it and move to the next one */ 228 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); 229 CurrentAddress += PAGE_SIZE; 230 continue; 231 } 232 233 /* Get the PDE offset */ 234 PdeOffset = MiAddressToPdeOffset(VirtualAddress); 235 236 /* Check if paging is actually turned on */ 237 if (Enabled) 238 { 239 /* Get the PDE entry using the self-map */ 240 Pde = MiAddressToPde(VirtualAddress); 241 } 242 else 243 { 244 /* Get it using our physical mappings */ 245 Pde = &MmPdpt[PdeOffset]; 246 PageTable = (PMMPDE)(Pde->u.Hard.PageFrameNumber << PAGE_SHIFT); 247 } 248 249 /* Check if we don't yet have a PDE */ 250 if (!Pde->u.Hard.Valid) 251 { 252 /* Allocate a page table */ 253 Status = MmPapAllocatePhysicalPagesInRange(&PageTableAddress, 254 BlLoaderPageDirectory, 255 1, 256 0, 257 0, 258 &MmMdlUnmappedAllocated, 259 0, 260 0); 261 if (!NT_SUCCESS(Status)) 262 { 263 EfiPrintf(L"PDE alloc failed!\r\n"); 264 EfiStall(1000000); 265 return STATUS_NO_MEMORY; 266 } 267 268 /* This is our page table */ 269 PageTable = (PVOID)(ULONG_PTR)PageTableAddress.QuadPart; 270 271 /* Build the PDE for it */ 272 Pde->u.Hard.PageFrameNumber = PageTableAddress.QuadPart >> PAGE_SHIFT; 273 Pde->u.Hard.Write = 1; 274 Pde->u.Hard.CacheDisable = 1; 275 Pde->u.Hard.WriteThrough = 1; 276 Pde->u.Hard.Valid = 1; 277 278 /* Check if paging is enabled */ 279 if (Enabled) 280 { 281 /* Then actually, get the page table's virtual address */ 282 PageTable = (PVOID)PAGE_ROUND_DOWN(MiAddressToPte(VirtualAddress)); 283 284 /* Flush the TLB */ 285 Mmx86FlushTlb(); 286 } 287 288 /* Zero out the page table */ 289 RtlZeroMemory(PageTable, PAGE_SIZE); 290 291 /* Reset caching attributes now */ 292 Pde->u.Hard.CacheDisable = 0; 293 Pde->u.Hard.WriteThrough = 0; 294 295 /* Check for paging again */ 296 if (Enabled) 297 { 298 /* Flush the TLB entry for the page table only */ 299 Mmx86FlushTlbEntry(PageTable); 300 } 301 } 302 303 /* Add a reference to this page table */ 304 MmArchReferencePage[PdeOffset]++; 305 306 /* Check if a physical address was given */ 307 if (PhysicalAddress.QuadPart != -1) 308 { 309 /* Check if paging is turned on */ 310 if (Enabled) 311 { 312 /* Get the PTE using the self-map */ 313 Pte = MiAddressToPte(VirtualAddress); 314 } 315 else 316 { 317 /* Get the PTE using physical addressing */ 318 Pte = &PageTable[MiAddressToPteOffset(VirtualAddress)]; 319 } 320 321 /* Build a valid PTE for it */ 322 Pte->u.Hard.PageFrameNumber = CurrentAddress >> PAGE_SHIFT; 323 Pte->u.Hard.Write = 1; 324 Pte->u.Hard.Valid = 1; 325 326 /* Check if this is uncached */ 327 if (CacheAttributes == BlMemoryUncached) 328 { 329 /* Set the flags */ 330 Pte->u.Hard.CacheDisable = 1; 331 Pte->u.Hard.WriteThrough = 1; 332 } 333 else if (CacheAttributes == BlMemoryWriteThrough) 334 { 335 /* It's write-through, set the flag */ 336 Pte->u.Hard.WriteThrough = 1; 337 } 338 } 339 340 /* Move to the next physical/virtual address */ 341 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); 342 CurrentAddress += PAGE_SIZE; 343 } 344 345 /* All done! */ 346 return STATUS_SUCCESS; 347 } 348 349 BOOLEAN 350 MmDefpTranslateVirtualAddress ( 351 _In_ PVOID VirtualAddress, 352 _Out_ PPHYSICAL_ADDRESS PhysicalAddress, 353 _Out_opt_ PULONG CacheAttributes 354 ) 355 { 356 PMMPDE Pde; 357 PMMPTE Pte; 358 PMMPTE PageTable; 359 BOOLEAN Enabled; 360 361 /* Is there no page directory yet? */ 362 if (!MmPdpt) 363 { 364 return FALSE; 365 } 366 367 /* Is paging enabled? */ 368 Enabled = BlMmIsTranslationEnabled(); 369 370 /* Check if paging is actually turned on */ 371 if (Enabled) 372 { 373 /* Get the PDE entry using the self-map */ 374 Pde = MiAddressToPde(VirtualAddress); 375 } 376 else 377 { 378 /* Get it using our physical mappings */ 379 Pde = &MmPdpt[MiAddressToPdeOffset(VirtualAddress)]; 380 } 381 382 /* Is the PDE valid? */ 383 if (!Pde->u.Hard.Valid) 384 { 385 return FALSE; 386 } 387 388 /* Check if paging is turned on */ 389 if (Enabled) 390 { 391 /* Get the PTE using the self-map */ 392 Pte = MiAddressToPte(VirtualAddress); 393 } 394 else 395 { 396 /* Get the PTE using physical addressing */ 397 PageTable = (PMMPTE)(Pde->u.Hard.PageFrameNumber << PAGE_SHIFT); 398 Pte = &PageTable[MiAddressToPteOffset(VirtualAddress)]; 399 } 400 401 /* Is the PTE valid? */ 402 if (!Pte->u.Hard.Valid) 403 { 404 return FALSE; 405 } 406 407 /* Does caller want the physical address? */ 408 if (PhysicalAddress) 409 { 410 /* Return it */ 411 PhysicalAddress->QuadPart = (Pte->u.Hard.PageFrameNumber << PAGE_SHIFT) + 412 BYTE_OFFSET(VirtualAddress); 413 } 414 415 /* Does caller want cache attributes? */ 416 if (CacheAttributes) 417 { 418 /* Not yet -- lie and say it's cached */ 419 EfiPrintf(L"Cache checking not yet enabled\r\n"); 420 *CacheAttributes = BlMemoryWriteBack; 421 } 422 423 /* It exists! */ 424 return TRUE; 425 } 426 427 NTSTATUS 428 MmMapPhysicalAddress ( 429 _Inout_ PPHYSICAL_ADDRESS PhysicalAddressPtr, 430 _Inout_ PVOID* VirtualAddressPtr, 431 _Inout_ PULONGLONG SizePtr, 432 _In_ ULONG CacheAttributes 433 ) 434 { 435 ULONGLONG Size; 436 ULONGLONG PhysicalAddress; 437 PVOID VirtualAddress; 438 PHYSICAL_ADDRESS TranslatedAddress; 439 ULONG_PTR CurrentAddress, VirtualAddressEnd; 440 NTSTATUS Status; 441 442 /* Fail if any parameters are missing */ 443 if (!(PhysicalAddressPtr) || !(VirtualAddressPtr) || !(SizePtr)) 444 { 445 return STATUS_INVALID_PARAMETER; 446 } 447 448 /* Fail if the size is over 32-bits */ 449 Size = *SizePtr; 450 if (Size > 0xFFFFFFFF) 451 { 452 return STATUS_INVALID_PARAMETER; 453 } 454 455 /* Nothing to do if we're in physical mode */ 456 if (MmTranslationType == BlNone) 457 { 458 return STATUS_SUCCESS; 459 } 460 461 /* Can't use virtual memory in real mode */ 462 if (CurrentExecutionContext->Mode == BlRealMode) 463 { 464 return STATUS_UNSUCCESSFUL; 465 } 466 467 /* Capture the current virtual and physical addresses */ 468 VirtualAddress = *VirtualAddressPtr; 469 PhysicalAddress = PhysicalAddressPtr->QuadPart; 470 471 /* Check if a physical address was requested */ 472 if (PhysicalAddress != 0xFFFFFFFF) 473 { 474 /* Round down the base addresses */ 475 PhysicalAddress = PAGE_ROUND_DOWN(PhysicalAddress); 476 VirtualAddress = (PVOID)PAGE_ROUND_DOWN(VirtualAddress); 477 478 /* Round up the size */ 479 Size = ROUND_TO_PAGES(PhysicalAddressPtr->QuadPart - 480 PhysicalAddress + 481 Size); 482 483 /* Loop every virtual page */ 484 CurrentAddress = (ULONG_PTR)VirtualAddress; 485 VirtualAddressEnd = CurrentAddress + Size - 1; 486 while (CurrentAddress < VirtualAddressEnd) 487 { 488 /* Get the physical page of this virtual page */ 489 if (MmArchTranslateVirtualAddress((PVOID)CurrentAddress, 490 &TranslatedAddress, 491 &CacheAttributes)) 492 { 493 /* Make sure the physical page of the virtual page, matches our page */ 494 if (TranslatedAddress.QuadPart != 495 (PhysicalAddress + 496 (CurrentAddress - (ULONG_PTR)VirtualAddress))) 497 { 498 /* There is an existing virtual mapping for a different address */ 499 EfiPrintf(L"Existing mapping exists: %lx vs %lx\r\n", 500 TranslatedAddress.QuadPart, 501 PhysicalAddress + (CurrentAddress - (ULONG_PTR)VirtualAddress)); 502 EfiStall(10000000); 503 return STATUS_INVALID_PARAMETER; 504 } 505 } 506 507 /* Try the next one */ 508 CurrentAddress += PAGE_SIZE; 509 } 510 } 511 512 /* Aactually do the mapping */ 513 TranslatedAddress.QuadPart = PhysicalAddress; 514 Status = Mmx86MapPhysicalAddress(TranslatedAddress, 515 VirtualAddress, 516 Size, 517 CacheAttributes); 518 if (!NT_SUCCESS(Status)) 519 { 520 EfiPrintf(L"Failed to map!: %lx\r\n", Status); 521 EfiStall(1000000); 522 return Status; 523 } 524 525 /* Return aligned/fixed up output parameters */ 526 PhysicalAddressPtr->QuadPart = PhysicalAddress; 527 *VirtualAddressPtr = VirtualAddress; 528 *SizePtr = Size; 529 530 /* Flush the TLB if paging is enabled */ 531 if (BlMmIsTranslationEnabled()) 532 { 533 Mmx86FlushTlb(); 534 } 535 536 /* All good! */ 537 return STATUS_SUCCESS; 538 } 539 540 NTSTATUS 541 Mmx86MapInitStructure ( 542 _In_ PVOID VirtualAddress, 543 _In_ ULONGLONG Size, 544 _In_ PHYSICAL_ADDRESS PhysicalAddress 545 ) 546 { 547 NTSTATUS Status; 548 549 /* Make a virtual mapping for this physical address */ 550 Status = MmMapPhysicalAddress(&PhysicalAddress, &VirtualAddress, &Size, 0); 551 if (!NT_SUCCESS(Status)) 552 { 553 return Status; 554 } 555 556 /* Nothing else to do if we're not in paging mode */ 557 if (MmTranslationType == BlNone) 558 { 559 return STATUS_SUCCESS; 560 } 561 562 /* Otherwise, remove this region from the list of free virtual ranges */ 563 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual, 564 BL_MM_REMOVE_VIRTUAL_REGION_FLAG, 565 (ULONG_PTR)VirtualAddress >> PAGE_SHIFT, 566 Size >> PAGE_SHIFT, 567 0); 568 if (!NT_SUCCESS(Status)) 569 { 570 /* Unmap the address if that failed */ 571 MmUnmapVirtualAddress(&VirtualAddress, &Size); 572 } 573 574 /* Return back to caller */ 575 return Status; 576 } 577 578 VOID 579 MmMdDbgDumpList ( 580 _In_ PBL_MEMORY_DESCRIPTOR_LIST DescriptorList, 581 _In_opt_ ULONG MaxCount 582 ) 583 { 584 ULONGLONG EndPage, VirtualEndPage; 585 PBL_MEMORY_DESCRIPTOR MemoryDescriptor; 586 PLIST_ENTRY NextEntry; 587 588 /* If no maximum was provided, use essentially infinite */ 589 if (MaxCount == 0) 590 { 591 MaxCount = 0xFFFFFFFF; 592 } 593 594 /* Loop the list as long as there's entries and max isn't reached */ 595 NextEntry = DescriptorList->First->Flink; 596 while ((NextEntry != DescriptorList->First) && (MaxCount--)) 597 { 598 /* Get the descriptor */ 599 MemoryDescriptor = CONTAINING_RECORD(NextEntry, 600 BL_MEMORY_DESCRIPTOR, 601 ListEntry); 602 603 /* Get the descriptor end page, and see if it was virtually mapepd */ 604 EndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount; 605 if (MemoryDescriptor->VirtualPage) 606 { 607 /* Get the virtual end page too, then */ 608 VirtualEndPage = MemoryDescriptor->VirtualPage + 609 MemoryDescriptor->PageCount; 610 } 611 else 612 { 613 VirtualEndPage = 0; 614 } 615 616 /* Print out the descriptor, physical range, virtual range, and type */ 617 EfiPrintf(L"%p - [%08llx-%08llx @ %08llx-%08llx]:%x\r\n", 618 MemoryDescriptor, 619 MemoryDescriptor->BasePage << PAGE_SHIFT, 620 (EndPage << PAGE_SHIFT) - 1, 621 MemoryDescriptor->VirtualPage << PAGE_SHIFT, 622 VirtualEndPage ? (VirtualEndPage << PAGE_SHIFT) - 1 : 0, 623 (ULONG)MemoryDescriptor->Type); 624 625 /* Next entry */ 626 NextEntry = NextEntry->Flink; 627 } 628 } 629 630 NTSTATUS 631 Mmx86pMapMemoryRegions ( 632 _In_ ULONG Phase, 633 _In_ PBL_MEMORY_DATA MemoryData 634 ) 635 { 636 BOOLEAN DoDeferred; 637 ULONG DescriptorCount; 638 PBL_MEMORY_DESCRIPTOR Descriptor; 639 ULONG FinalOffset; 640 PHYSICAL_ADDRESS PhysicalAddress; 641 ULONGLONG Size; 642 NTSTATUS Status; 643 PVOID VirtualAddress; 644 BL_MEMORY_DESCRIPTOR_LIST FirmwareMdl; 645 PLIST_ENTRY Head, NextEntry; 646 647 /* Check which phase this is */ 648 if (Phase == 1) 649 { 650 /* In phase 1 we don't initialize deferred mappings */ 651 DoDeferred = FALSE; 652 } 653 else 654 { 655 /* Don't do anything if there's nothing to initialize */ 656 if (!MmDeferredMappingCount) 657 { 658 return STATUS_SUCCESS; 659 } 660 661 /* We'll do deferred descriptors in phase 2 */ 662 DoDeferred = TRUE; 663 } 664 665 /* 666 * Because BL supports cross x86-x64 application launches and a LIST_ENTRY 667 * is of variable size, care must be taken here to ensure that we see a 668 * consistent view of descriptors. BL uses some offset magic to figure out 669 * where the data actually starts, since everything is ULONGLONG past the 670 * LIST_ENTRY itself 671 */ 672 FinalOffset = MemoryData->MdListOffset + MemoryData->DescriptorOffset; 673 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)MemoryData + FinalOffset - 674 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR, BasePage)); 675 676 /* Scan all of them */ 677 DescriptorCount = MemoryData->DescriptorCount; 678 while (DescriptorCount != 0) 679 { 680 /* Ignore application data */ 681 if (Descriptor->Type != BlApplicationData) 682 { 683 /* If this is a ramdisk, do it in phase 2 */ 684 if ((Descriptor->Type == BlLoaderRamDisk) == DoDeferred) 685 { 686 /* Get the current physical address and size */ 687 PhysicalAddress.QuadPart = Descriptor->BasePage << PAGE_SHIFT; 688 Size = Descriptor->PageCount << PAGE_SHIFT; 689 690 /* Check if it was already mapped */ 691 if (Descriptor->VirtualPage) 692 { 693 /* Use the existing address */ 694 VirtualAddress = (PVOID)(ULONG_PTR)(Descriptor->VirtualPage << PAGE_SHIFT); 695 } 696 else 697 { 698 /* Use the physical address */ 699 VirtualAddress = (PVOID)(ULONG_PTR)PhysicalAddress.QuadPart; 700 } 701 702 /* Crete the mapping */ 703 Status = Mmx86MapInitStructure(VirtualAddress, 704 Size, 705 PhysicalAddress); 706 if (!NT_SUCCESS(Status)) 707 { 708 return Status; 709 } 710 } 711 712 /* Check if we're in phase 1 and deferring RAM disk */ 713 if ((Phase == 1) && (Descriptor->Type == BlLoaderRamDisk)) 714 { 715 MmDeferredMappingCount++; 716 } 717 } 718 719 /* Move on to the next descriptor */ 720 DescriptorCount--; 721 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)Descriptor + MemoryData->DescriptorSize); 722 } 723 724 /* In phase 1, also do UEFI mappings */ 725 if (Phase != 2) 726 { 727 /* Get the memory map */ 728 MmMdInitializeListHead(&FirmwareMdl); 729 Status = MmFwGetMemoryMap(&FirmwareMdl, BL_MM_FLAG_REQUEST_COALESCING); 730 if (!NT_SUCCESS(Status)) 731 { 732 return Status; 733 } 734 735 /* Iterate over it */ 736 Head = FirmwareMdl.First; 737 NextEntry = Head->Flink; 738 while (NextEntry != Head) 739 { 740 /* Check if this is a UEFI-related descriptor, unless it's the self-map page */ 741 Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); 742 if (((Descriptor->Type == BlEfiBootMemory) || 743 (Descriptor->Type == BlEfiRuntimeCodeMemory) || 744 (Descriptor->Type == BlEfiRuntimeDataMemory) || // WINBUG? 745 (Descriptor->Type == BlLoaderMemory)) && 746 ((Descriptor->BasePage << PAGE_SHIFT) != Mmx86SelfMapBase.QuadPart)) 747 { 748 /* Identity-map it */ 749 PhysicalAddress.QuadPart = Descriptor->BasePage << PAGE_SHIFT; 750 Status = Mmx86MapInitStructure((PVOID)((ULONG_PTR)Descriptor->BasePage << PAGE_SHIFT), 751 Descriptor->PageCount << PAGE_SHIFT, 752 PhysicalAddress); 753 if (!NT_SUCCESS(Status)) 754 { 755 return Status; 756 } 757 } 758 759 /* Move to the next descriptor */ 760 NextEntry = NextEntry->Flink; 761 } 762 763 /* Reset */ 764 NextEntry = Head->Flink; 765 while (NextEntry != Head) 766 { 767 /* Get the descriptor */ 768 Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); 769 770 /* Skip to the next entry before we free */ 771 NextEntry = NextEntry->Flink; 772 773 /* Remove and free it */ 774 MmMdRemoveDescriptorFromList(&FirmwareMdl, Descriptor); 775 MmMdFreeDescriptor(Descriptor); 776 } 777 } 778 779 /* All library mappings identity mapped now */ 780 return STATUS_SUCCESS; 781 } 782 783 NTSTATUS 784 Mmx86InitializeMemoryMap ( 785 _In_ ULONG Phase, 786 _In_ PBL_MEMORY_DATA MemoryData 787 ) 788 { 789 ULONG ImageSize; 790 PVOID ImageBase; 791 KDESCRIPTOR Gdt, Idt; 792 NTSTATUS Status; 793 PHYSICAL_ADDRESS PhysicalAddress; 794 795 /* If this is phase 2, map the memory regions */ 796 if (Phase != 1) 797 { 798 return Mmx86pMapMemoryRegions(Phase, MemoryData); 799 } 800 801 /* Get the application image base/size */ 802 Status = BlGetApplicationBaseAndSize(&ImageBase, &ImageSize); 803 if (!NT_SUCCESS(Status)) 804 { 805 return Status; 806 } 807 808 /* Map the image back at the same place */ 809 PhysicalAddress.QuadPart = (ULONG_PTR)ImageBase; 810 Status = Mmx86MapInitStructure(ImageBase, ImageSize, PhysicalAddress); 811 if (!NT_SUCCESS(Status)) 812 { 813 return Status; 814 } 815 816 /* Map the first 4MB of memory */ 817 PhysicalAddress.QuadPart = 0; 818 Status = Mmx86MapInitStructure(NULL, 4 * 1024 * 1024, PhysicalAddress); 819 if (!NT_SUCCESS(Status)) 820 { 821 return Status; 822 } 823 824 /* Map the GDT */ 825 _sgdt(&Gdt.Limit); 826 PhysicalAddress.QuadPart = Gdt.Base; 827 Status = Mmx86MapInitStructure((PVOID)Gdt.Base, Gdt.Limit + 1, PhysicalAddress); 828 if (!NT_SUCCESS(Status)) 829 { 830 return Status; 831 } 832 833 /* Map the IDT */ 834 __sidt(&Idt.Limit); 835 PhysicalAddress.QuadPart = Idt.Base; 836 Status = Mmx86MapInitStructure((PVOID)Idt.Base, Idt.Limit + 1, PhysicalAddress); 837 if (!NT_SUCCESS(Status)) 838 { 839 return Status; 840 } 841 842 /* Map the reference page */ 843 PhysicalAddress.QuadPart = (ULONG_PTR)MmArchReferencePage; 844 Status = Mmx86MapInitStructure(MmArchReferencePage, 845 MmArchReferencePageSize, 846 PhysicalAddress); 847 if (!NT_SUCCESS(Status)) 848 { 849 return Status; 850 } 851 852 /* More to do */ 853 return Mmx86pMapMemoryRegions(Phase, MemoryData); 854 } 855 856 NTSTATUS 857 MmDefInitializeTranslation ( 858 _In_ PBL_MEMORY_DATA MemoryData, 859 _In_ BL_TRANSLATION_TYPE TranslationType 860 ) 861 { 862 NTSTATUS Status; 863 PHYSICAL_ADDRESS PhysicalAddress; 864 ULONG PdeIndex; 865 866 /* Set the global function pointers for memory translation */ 867 Mmx86TranslateVirtualAddress = MmDefpTranslateVirtualAddress; 868 Mmx86MapPhysicalAddress = MmDefpMapPhysicalAddress; 869 Mmx86UnmapVirtualAddress = MmDefpUnmapVirtualAddress; 870 Mmx86RemapVirtualAddress = MmDefpRemapVirtualAddress; 871 Mmx86FlushTlb = MmDefpFlushTlb; 872 Mmx86FlushTlbEntry = MmDefpFlushTlbEntry; 873 Mmx86DestroySelfMap = MmDefpDestroySelfMap; 874 875 /* Check what mode we're currently in */ 876 if (TranslationType == BlVirtual) 877 { 878 EfiPrintf(L"Virtual->Virtual not yet supported\r\n"); 879 return STATUS_NOT_IMPLEMENTED; 880 } 881 else if (TranslationType != BlNone) 882 { 883 /* Not even Windows supports PAE->Virtual downgrade */ 884 return STATUS_NOT_IMPLEMENTED; 885 } 886 887 /* The None->Virtual case */ 888 MmPdpt = NULL; 889 Mmx86SelfMapBase.QuadPart = 0; 890 MmArchReferencePage = NULL; 891 892 /* Truncate all memory above 4GB so that we don't use it */ 893 Status = MmPaTruncateMemory(0x100000); 894 if (!NT_SUCCESS(Status)) 895 { 896 goto Failure; 897 } 898 899 /* Allocate a page directory */ 900 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress, 901 BlLoaderPageDirectory, 902 1, 903 0, 904 0, 905 &MmMdlUnmappedAllocated, 906 0, 907 0); 908 if (!NT_SUCCESS(Status)) 909 { 910 goto Failure; 911 } 912 913 /* Zero out the page directory */ 914 MmPdpt = (PVOID)PhysicalAddress.LowPart; 915 RtlZeroMemory(MmPdpt, PAGE_SIZE); 916 917 /* Set the page size */ 918 MmArchReferencePageSize = PAGE_SIZE; 919 920 /* Allocate the self-map page */ 921 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress, 922 BlLoaderReferencePage, 923 1, 924 0, 925 0, 926 &MmMdlUnmappedAllocated, 927 0, 928 0); 929 if (!NT_SUCCESS(Status)) 930 { 931 goto Failure; 932 } 933 934 /* Set the reference page */ 935 MmArchReferencePage = (PVOID)PhysicalAddress.LowPart; 936 937 /* Zero it out */ 938 RtlZeroMemory(MmArchReferencePage, MmArchReferencePageSize); 939 940 /* Allocate 4MB worth of self-map pages */ 941 Status = MmPaReserveSelfMapPages(&Mmx86SelfMapBase, 942 (4 * 1024 * 1024) >> PAGE_SHIFT, 943 (4 * 1024 * 1024) >> PAGE_SHIFT); 944 if (!NT_SUCCESS(Status)) 945 { 946 goto Failure; 947 } 948 949 /* Zero them out */ 950 RtlZeroMemory((PVOID)Mmx86SelfMapBase.LowPart, 4 * 1024 * 1024); 951 EfiPrintf(L"PDPT at 0x%p Reference Page at 0x%p Self-map at 0x%p\r\n", 952 MmPdpt, MmArchReferencePage, Mmx86SelfMapBase.LowPart); 953 954 /* Align PTE base to 4MB region */ 955 MmPteBase = (PVOID)(Mmx86SelfMapBase.LowPart & ~0x3FFFFF); 956 957 /* The PDE is the PTE of the PTE base */ 958 MmPdeBase = MiAddressToPte(MmPteBase); 959 PdeIndex = MiAddressToPdeOffset(MmPdeBase); 960 MmPdpt[PdeIndex].u.Hard.Valid = 1; 961 MmPdpt[PdeIndex].u.Hard.Write = 1; 962 MmPdpt[PdeIndex].u.Hard.PageFrameNumber = (ULONG_PTR)MmPdpt >> PAGE_SHIFT; 963 MmArchReferencePage[PdeIndex]++; 964 965 /* Remove PTE_BASE from free virtual memory */ 966 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual, 967 BL_MM_REMOVE_VIRTUAL_REGION_FLAG, 968 PTE_BASE >> PAGE_SHIFT, 969 (4 * 1024 * 1024) >> PAGE_SHIFT, 970 0); 971 if (!NT_SUCCESS(Status)) 972 { 973 goto Failure; 974 } 975 976 /* Remove HAL_HEAP from free virtual memory */ 977 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual, 978 BL_MM_REMOVE_VIRTUAL_REGION_FLAG, 979 MM_HAL_VA_START >> PAGE_SHIFT, 980 (4 * 1024 * 1024) >> PAGE_SHIFT, 981 0); 982 if (!NT_SUCCESS(Status)) 983 { 984 goto Failure; 985 } 986 987 /* Initialize the virtual->physical memory mappings */ 988 Status = Mmx86InitializeMemoryMap(1, MemoryData); 989 if (!NT_SUCCESS(Status)) 990 { 991 goto Failure; 992 } 993 994 /* Turn on paging with the new CR3 */ 995 __writecr3((ULONG_PTR)MmPdpt); 996 BlpArchEnableTranslation(); 997 EfiPrintf(L"Paging... %d\r\n", BlMmIsTranslationEnabled()); 998 999 /* Return success */ 1000 return Status; 1001 1002 Failure: 1003 /* Free reference page if we allocated it */ 1004 if (MmArchReferencePage) 1005 { 1006 PhysicalAddress.QuadPart = (ULONG_PTR)MmArchReferencePage; 1007 BlMmFreePhysicalPages(PhysicalAddress); 1008 } 1009 1010 /* Free page directory if we allocated it */ 1011 if (MmPdpt) 1012 { 1013 PhysicalAddress.QuadPart = (ULONG_PTR)MmPdpt; 1014 BlMmFreePhysicalPages(PhysicalAddress); 1015 } 1016 1017 /* Free the self map if we allocated it */ 1018 if (Mmx86SelfMapBase.QuadPart) 1019 { 1020 MmPaReleaseSelfMapPages(Mmx86SelfMapBase); 1021 } 1022 1023 /* All done */ 1024 return Status; 1025 } 1026 1027 NTSTATUS 1028 MmArchInitialize ( 1029 _In_ ULONG Phase, 1030 _In_ PBL_MEMORY_DATA MemoryData, 1031 _In_ BL_TRANSLATION_TYPE TranslationType, 1032 _In_ BL_TRANSLATION_TYPE RequestedTranslationType 1033 ) 1034 { 1035 NTSTATUS Status; 1036 ULONGLONG IncreaseUserVa, PerfCounter, CpuRandom; 1037 CPU_INFO CpuInfo; 1038 1039 /* For phase 2, just map deferred regions */ 1040 if (Phase != 1) 1041 { 1042 return Mmx86pMapMemoryRegions(2, MemoryData); 1043 } 1044 1045 /* What translation type are we switching to? */ 1046 switch (RequestedTranslationType) 1047 { 1048 /* Physical memory */ 1049 case BlNone: 1050 1051 /* Initialize everything to default/null values */ 1052 MmArchLargePageSize = 1; 1053 MmArchKsegBase = 0; 1054 MmArchKsegBias = 0; 1055 MmArchKsegAddressRange.Minimum = 0; 1056 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0; 1057 MmArchTopOfApplicationAddressSpace = 0; 1058 Mmx86SelfMapBase.QuadPart = 0; 1059 1060 /* Set stub functions */ 1061 BlMmRelocateSelfMap = MmArchNullFunction; 1062 BlMmFlushTlb = MmArchNullFunction; 1063 1064 /* Set success */ 1065 Status = STATUS_SUCCESS; 1066 break; 1067 1068 case BlVirtual: 1069 1070 /* Set the large page size to 1024 pages (4MB) */ 1071 MmArchLargePageSize = (4 * 1024 * 1024) / PAGE_SIZE; 1072 1073 /* Check if /USERVA option was used */ 1074 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData, 1075 BcdOSLoaderInteger_IncreaseUserVa, 1076 &IncreaseUserVa); 1077 if (NT_SUCCESS(Status) && (IncreaseUserVa)) 1078 { 1079 /* Yes -- load the kernel at 0xE0000000 instead */ 1080 MmArchKsegBase = 0xE0000000; 1081 } 1082 else 1083 { 1084 /* Nope, load at the standard 2GB split */ 1085 MmArchKsegBase = 0x80000000; 1086 } 1087 1088 /* Check if CPUID 01h is supported */ 1089 CpuRandom = 0; 1090 if (BlArchIsCpuIdFunctionSupported(1)) 1091 { 1092 /* Call it */ 1093 BlArchCpuId(1, 0, &CpuInfo); 1094 1095 /* Check if RDRAND is supported */ 1096 if (CpuInfo.Ecx & 0x40000000) 1097 { 1098 EfiPrintf(L"Your CPU can do RDRAND! Good for you!\r\n"); 1099 CpuRandom = 0; 1100 } 1101 } 1102 1103 /* Read the TSC */ 1104 PerfCounter = BlArchGetPerformanceCounter(); 1105 PerfCounter >>= 4; 1106 _rotl16(PerfCounter, 5); 1107 1108 /* Set the address range */ 1109 MmArchKsegAddressRange.Minimum = 0; 1110 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0; 1111 1112 /* Set the KASLR bias */ 1113 MmArchKsegBias = ((PerfCounter ^ CpuRandom) & 0xFFF) << 12; 1114 MmArchKsegBias = 0; 1115 MmArchKsegBase += MmArchKsegBias; 1116 1117 /* Set the kernel range */ 1118 MmArchKsegAddressRange.Minimum = MmArchKsegBase; 1119 MmArchKsegAddressRange.Maximum = (ULONGLONG)~0; 1120 1121 /* Set the boot application top maximum */ 1122 MmArchTopOfApplicationAddressSpace = 0x70000000 - 1; // Windows bug 1123 1124 /* Initialize virtual address space translation */ 1125 Status = MmDefInitializeTranslation(MemoryData, TranslationType); 1126 if (NT_SUCCESS(Status)) 1127 { 1128 /* Set stub functions */ 1129 BlMmRelocateSelfMap = MmDefRelocateSelfMap; 1130 BlMmFlushTlb = Mmx86FlushTlb; 1131 BlMmMoveVirtualAddressRange = MmDefMoveVirtualAddressRange; 1132 BlMmZeroVirtualAddressRange = MmDefZeroVirtualAddressRange; 1133 } 1134 break; 1135 1136 case BlPae: 1137 1138 /* We don't support PAE */ 1139 Status = STATUS_NOT_SUPPORTED; 1140 break; 1141 1142 default: 1143 1144 /* Invalid architecture type*/ 1145 Status = STATUS_INVALID_PARAMETER; 1146 break; 1147 } 1148 1149 /* Back to caller */ 1150 return Status; 1151 } 1152