MtrrLib.c revision c878cee473ac03642d7692b0f641c2e83dede9c4
1/** @file 2 MTRR setting library 3 4 Copyright (c) 2008 - 2012, 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 <Base.h> 16 17#include <Library/MtrrLib.h> 18#include <Library/BaseLib.h> 19#include <Library/CpuLib.h> 20#include <Library/BaseMemoryLib.h> 21#include <Library/DebugLib.h> 22 23// 24// Context to save and restore when MTRRs are programmed 25// 26typedef struct { 27 UINTN Cr4; 28 BOOLEAN InterruptState; 29} MTRR_CONTEXT; 30 31// 32// This table defines the offset, base and length of the fixed MTRRs 33// 34CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = { 35 { 36 MTRR_LIB_IA32_MTRR_FIX64K_00000, 37 0, 38 SIZE_64KB 39 }, 40 { 41 MTRR_LIB_IA32_MTRR_FIX16K_80000, 42 0x80000, 43 SIZE_16KB 44 }, 45 { 46 MTRR_LIB_IA32_MTRR_FIX16K_A0000, 47 0xA0000, 48 SIZE_16KB 49 }, 50 { 51 MTRR_LIB_IA32_MTRR_FIX4K_C0000, 52 0xC0000, 53 SIZE_4KB 54 }, 55 { 56 MTRR_LIB_IA32_MTRR_FIX4K_C8000, 57 0xC8000, 58 SIZE_4KB 59 }, 60 { 61 MTRR_LIB_IA32_MTRR_FIX4K_D0000, 62 0xD0000, 63 SIZE_4KB 64 }, 65 { 66 MTRR_LIB_IA32_MTRR_FIX4K_D8000, 67 0xD8000, 68 SIZE_4KB 69 }, 70 { 71 MTRR_LIB_IA32_MTRR_FIX4K_E0000, 72 0xE0000, 73 SIZE_4KB 74 }, 75 { 76 MTRR_LIB_IA32_MTRR_FIX4K_E8000, 77 0xE8000, 78 SIZE_4KB 79 }, 80 { 81 MTRR_LIB_IA32_MTRR_FIX4K_F0000, 82 0xF0000, 83 SIZE_4KB 84 }, 85 { 86 MTRR_LIB_IA32_MTRR_FIX4K_F8000, 87 0xF8000, 88 SIZE_4KB 89 }, 90}; 91 92// 93// Lookup table used to print MTRRs 94// 95GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = { 96 "UC", // CacheUncacheable 97 "WC", // CacheWriteCombining 98 "R*", // Invalid 99 "R*", // Invalid 100 "WT", // CacheWriteThrough 101 "WP", // CacheWriteProtected 102 "WB", // CacheWriteBack 103 "R*" // Invalid 104}; 105 106/** 107 Returns the variable MTRR count for the CPU. 108 109 @return Variable MTRR count 110 111**/ 112UINT32 113EFIAPI 114GetVariableMtrrCount ( 115 VOID 116 ) 117{ 118 UINT32 VariableMtrrCount; 119 120 if (!IsMtrrSupported ()) { 121 return 0; 122 } 123 124 VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK); 125 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); 126 127 return VariableMtrrCount; 128} 129 130/** 131 Returns the firmware usable variable MTRR count for the CPU. 132 133 @return Firmware usable variable MTRR count 134 135**/ 136UINT32 137EFIAPI 138GetFirmwareVariableMtrrCount ( 139 VOID 140 ) 141{ 142 UINT32 VariableMtrrCount; 143 144 VariableMtrrCount = GetVariableMtrrCount (); 145 if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) { 146 return 0; 147 } 148 149 return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER; 150} 151 152/** 153 Returns the default MTRR cache type for the system. 154 155 @return The default MTRR cache type. 156 157**/ 158MTRR_MEMORY_CACHE_TYPE 159EFIAPI 160MtrrGetDefaultMemoryType ( 161 VOID 162 ) 163{ 164 if (!IsMtrrSupported ()) { 165 return CacheUncacheable; 166 } 167 168 return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7); 169} 170 171/** 172 Preparation before programming MTRR. 173 174 This function will do some preparation for programming MTRRs: 175 disable cache, invalid cache and disable MTRR caching functionality 176 177 @param[out] Pointer to context to save 178 179**/ 180VOID 181PreMtrrChange ( 182 OUT MTRR_CONTEXT *MtrrContext 183 ) 184{ 185 // 186 // Disable interrupts and save current interrupt state 187 // 188 MtrrContext->InterruptState = SaveAndDisableInterrupts(); 189 190 // 191 // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29) 192 // 193 AsmDisableCache (); 194 195 // 196 // Save original CR4 value and clear PGE flag (Bit 7) 197 // 198 MtrrContext->Cr4 = AsmReadCr4 (); 199 AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7)); 200 201 // 202 // Flush all TLBs 203 // 204 CpuFlushTlb (); 205 206 // 207 // Disable Mtrrs 208 // 209 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0); 210} 211 212/** 213 Cleaning up after programming MTRRs. 214 215 This function will do some clean up after programming MTRRs: 216 Flush all TLBs, re-enable caching, restore CR4. 217 218 @param[in] Pointer to context to restore 219 220**/ 221VOID 222PostMtrrChangeEnableCache ( 223 IN MTRR_CONTEXT *MtrrContext 224 ) 225{ 226 // 227 // Flush all TLBs 228 // 229 CpuFlushTlb (); 230 231 // 232 // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29) 233 // 234 AsmEnableCache (); 235 236 // 237 // Restore original CR4 value 238 // 239 AsmWriteCr4 (MtrrContext->Cr4); 240 241 // 242 // Restore original interrupt state 243 // 244 SetInterruptState (MtrrContext->InterruptState); 245} 246 247/** 248 Cleaning up after programming MTRRs. 249 250 This function will do some clean up after programming MTRRs: 251 enable MTRR caching functionality, and enable cache 252 253 @param[in] Pointer to context to restore 254 255**/ 256VOID 257PostMtrrChange ( 258 IN MTRR_CONTEXT *MtrrContext 259 ) 260{ 261 // 262 // Enable Cache MTRR 263 // 264 AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3); 265 266 PostMtrrChangeEnableCache (MtrrContext); 267} 268 269 270/** 271 Programs fixed MTRRs registers. 272 273 @param MemoryCacheType The memory type to set. 274 @param Base The base address of memory range. 275 @param Length The length of memory range. 276 277 @retval RETURN_SUCCESS The cache type was updated successfully 278 @retval RETURN_UNSUPPORTED The requested range or cache type was invalid 279 for the fixed MTRRs. 280 281**/ 282RETURN_STATUS 283ProgramFixedMtrr ( 284 IN UINT64 MemoryCacheType, 285 IN OUT UINT64 *Base, 286 IN OUT UINT64 *Length 287 ) 288{ 289 UINT32 MsrNum; 290 UINT32 ByteShift; 291 UINT64 TempQword; 292 UINT64 OrMask; 293 UINT64 ClearMask; 294 295 TempQword = 0; 296 OrMask = 0; 297 ClearMask = 0; 298 299 for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) { 300 if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) && 301 (*Base < 302 ( 303 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress + 304 (8 * mMtrrLibFixedMtrrTable[MsrNum].Length) 305 ) 306 ) 307 ) { 308 break; 309 } 310 } 311 312 if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) { 313 return RETURN_UNSUPPORTED; 314 } 315 316 // 317 // We found the fixed MTRR to be programmed 318 // 319 for (ByteShift = 0; ByteShift < 8; ByteShift++) { 320 if (*Base == 321 ( 322 mMtrrLibFixedMtrrTable[MsrNum].BaseAddress + 323 (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length) 324 ) 325 ) { 326 break; 327 } 328 } 329 330 if (ByteShift == 8) { 331 return RETURN_UNSUPPORTED; 332 } 333 334 for ( 335 ; 336 ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length)); 337 ByteShift++ 338 ) { 339 OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8)); 340 ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8)); 341 *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length; 342 *Base += mMtrrLibFixedMtrrTable[MsrNum].Length; 343 } 344 345 if (ByteShift < 8 && (*Length != 0)) { 346 return RETURN_UNSUPPORTED; 347 } 348 349 TempQword = 350 (AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask; 351 AsmWriteMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr, TempQword); 352 return RETURN_SUCCESS; 353} 354 355 356/** 357 Get the attribute of variable MTRRs. 358 359 This function shadows the content of variable MTRRs into an 360 internal array: VariableMtrr. 361 362 @param MtrrValidBitsMask The mask for the valid bit of the MTRR 363 @param MtrrValidAddressMask The valid address mask for MTRR 364 @param VariableMtrr The array to shadow variable MTRRs content 365 366 @return The return value of this paramter indicates the 367 number of MTRRs which has been used. 368 369**/ 370UINT32 371EFIAPI 372MtrrGetMemoryAttributeInVariableMtrr ( 373 IN UINT64 MtrrValidBitsMask, 374 IN UINT64 MtrrValidAddressMask, 375 OUT VARIABLE_MTRR *VariableMtrr 376 ) 377{ 378 UINTN Index; 379 UINT32 MsrNum; 380 UINT32 UsedMtrr; 381 UINT32 FirmwareVariableMtrrCount; 382 UINT32 VariableMtrrEnd; 383 384 if (!IsMtrrSupported ()) { 385 return 0; 386 } 387 388 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); 389 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; 390 391 ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR); 392 UsedMtrr = 0; 393 394 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0; 395 ( 396 (MsrNum < VariableMtrrEnd) && 397 (Index < FirmwareVariableMtrrCount) 398 ); 399 MsrNum += 2 400 ) { 401 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) { 402 VariableMtrr[Index].Msr = MsrNum; 403 VariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) & 404 MtrrValidAddressMask); 405 VariableMtrr[Index].Length = ((~(AsmReadMsr64 (MsrNum + 1) & 406 MtrrValidAddressMask) 407 ) & 408 MtrrValidBitsMask 409 ) + 1; 410 VariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & 0x0ff); 411 VariableMtrr[Index].Valid = TRUE; 412 VariableMtrr[Index].Used = TRUE; 413 UsedMtrr = UsedMtrr + 1; 414 Index++; 415 } 416 } 417 return UsedMtrr; 418} 419 420 421/** 422 Checks overlap between given memory range and MTRRs. 423 424 @param Start The start address of memory range. 425 @param End The end address of memory range. 426 @param VariableMtrr The array to shadow variable MTRRs content 427 428 @retval TRUE Overlap exists. 429 @retval FALSE No overlap. 430 431**/ 432BOOLEAN 433CheckMemoryAttributeOverlap ( 434 IN PHYSICAL_ADDRESS Start, 435 IN PHYSICAL_ADDRESS End, 436 IN VARIABLE_MTRR *VariableMtrr 437 ) 438{ 439 UINT32 Index; 440 441 for (Index = 0; Index < 6; Index++) { 442 if ( 443 VariableMtrr[Index].Valid && 444 !( 445 (Start > (VariableMtrr[Index].BaseAddress + 446 VariableMtrr[Index].Length - 1) 447 ) || 448 (End < VariableMtrr[Index].BaseAddress) 449 ) 450 ) { 451 return TRUE; 452 } 453 } 454 455 return FALSE; 456} 457 458 459/** 460 Marks a variable MTRR as non-valid. 461 462 @param Index The index of the array VariableMtrr to be invalidated 463 @param VariableMtrr The array to shadow variable MTRRs content 464 @param UsedMtrr The number of MTRRs which has already been used 465 466**/ 467VOID 468InvalidateShadowMtrr ( 469 IN UINTN Index, 470 IN VARIABLE_MTRR *VariableMtrr, 471 OUT UINT32 *UsedMtrr 472 ) 473{ 474 VariableMtrr[Index].Valid = FALSE; 475 *UsedMtrr = *UsedMtrr - 1; 476} 477 478 479/** 480 Combine memory attributes. 481 482 If overlap exists between given memory range and MTRRs, try to combine them. 483 484 @param Attributes The memory type to set. 485 @param Base The base address of memory range. 486 @param Length The length of memory range. 487 @param VariableMtrr The array to shadow variable MTRRs content 488 @param UsedMtrr The number of MTRRs which has already been used 489 @param OverwriteExistingMtrr Returns whether an existing MTRR was used 490 491 @retval EFI_SUCCESS Memory region successfully combined. 492 @retval EFI_ACCESS_DENIED Memory region cannot be combined. 493 494**/ 495RETURN_STATUS 496CombineMemoryAttribute ( 497 IN UINT64 Attributes, 498 IN OUT UINT64 *Base, 499 IN OUT UINT64 *Length, 500 IN VARIABLE_MTRR *VariableMtrr, 501 IN OUT UINT32 *UsedMtrr, 502 OUT BOOLEAN *OverwriteExistingMtrr 503 ) 504{ 505 UINT32 Index; 506 UINT64 CombineStart; 507 UINT64 CombineEnd; 508 UINT64 MtrrEnd; 509 UINT64 EndAddress; 510 UINT32 FirmwareVariableMtrrCount; 511 BOOLEAN CoveredByExistingMtrr; 512 513 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); 514 515 *OverwriteExistingMtrr = FALSE; 516 CoveredByExistingMtrr = FALSE; 517 EndAddress = *Base +*Length - 1; 518 519 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) { 520 521 MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1; 522 if ( 523 !VariableMtrr[Index].Valid || 524 ( 525 *Base > (MtrrEnd) || 526 (EndAddress < VariableMtrr[Index].BaseAddress) 527 ) 528 ) { 529 continue; 530 } 531 532 // 533 // Combine same attribute MTRR range 534 // 535 if (Attributes == VariableMtrr[Index].Type) { 536 // 537 // if the Mtrr range contain the request range, set a flag, then continue to 538 // invalidate any MTRR of the same request range with higher priority cache type. 539 // 540 if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) { 541 CoveredByExistingMtrr = TRUE; 542 continue; 543 } 544 // 545 // invalid this MTRR, and program the combine range 546 // 547 CombineStart = 548 (*Base) < VariableMtrr[Index].BaseAddress ? 549 (*Base) : 550 VariableMtrr[Index].BaseAddress; 551 CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd; 552 553 // 554 // Record the MTRR usage status in VariableMtrr array. 555 // 556 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr); 557 *Base = CombineStart; 558 *Length = CombineEnd - CombineStart + 1; 559 EndAddress = CombineEnd; 560 *OverwriteExistingMtrr = TRUE; 561 continue; 562 } else { 563 // 564 // The cache type is different, but the range is convered by one MTRR 565 // 566 if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) { 567 InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr); 568 continue; 569 } 570 571 } 572 573 if ((Attributes== MTRR_CACHE_WRITE_THROUGH && 574 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) || 575 (Attributes == MTRR_CACHE_WRITE_BACK && 576 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) || 577 (Attributes == MTRR_CACHE_UNCACHEABLE) || 578 (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) 579 ) { 580 *OverwriteExistingMtrr = TRUE; 581 continue; 582 } 583 // 584 // Other type memory overlap is invalid 585 // 586 return RETURN_ACCESS_DENIED; 587 } 588 589 if (CoveredByExistingMtrr) { 590 *Length = 0; 591 } 592 593 return RETURN_SUCCESS; 594} 595 596 597/** 598 Calculate the maximum value which is a power of 2, but less the MemoryLength. 599 600 @param MemoryLength The number to pass in. 601 @return The maximum value which is align to power of 2 and less the MemoryLength 602 603**/ 604UINT64 605Power2MaxMemory ( 606 IN UINT64 MemoryLength 607 ) 608{ 609 UINT64 Result; 610 611 if (RShiftU64 (MemoryLength, 32) != 0) { 612 Result = LShiftU64 ( 613 (UINT64) GetPowerOfTwo32 ( 614 (UINT32) RShiftU64 (MemoryLength, 32) 615 ), 616 32 617 ); 618 } else { 619 Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength); 620 } 621 622 return Result; 623} 624 625 626/** 627 Determine the MTRR numbers used to program a memory range. 628 629 This function first checks the alignment of the base address. If the alignment of the base address <= Length, 630 cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment. 631 Repeat the step until alignment > Length. 632 633 Then this function determines which direction of programming the variable MTRRs for the remaining length 634 will use fewer MTRRs. 635 636 @param BaseAddress Length of Memory to program MTRR 637 @param Length Length of Memory to program MTRR 638 @param MtrrNumber Pointer to the number of necessary MTRRs 639 640 @retval TRUE Positive direction is better. 641 FALSE Negtive direction is better. 642 643**/ 644BOOLEAN 645GetMtrrNumberAndDirection ( 646 IN UINT64 BaseAddress, 647 IN UINT64 Length, 648 IN UINTN *MtrrNumber 649 ) 650{ 651 UINT64 TempQword; 652 UINT64 Alignment; 653 UINT32 Positive; 654 UINT32 Subtractive; 655 656 *MtrrNumber = 0; 657 658 if (BaseAddress != 0) { 659 do { 660 // 661 // Calculate the alignment of the base address. 662 // 663 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); 664 665 if (Alignment > Length) { 666 break; 667 } 668 669 (*MtrrNumber)++; 670 BaseAddress += Alignment; 671 Length -= Alignment; 672 } while (TRUE); 673 674 if (Length == 0) { 675 return TRUE; 676 } 677 } 678 679 TempQword = Length; 680 Positive = 0; 681 Subtractive = 0; 682 683 do { 684 TempQword -= Power2MaxMemory (TempQword); 685 Positive++; 686 } while (TempQword != 0); 687 688 TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length; 689 Subtractive++; 690 do { 691 TempQword -= Power2MaxMemory (TempQword); 692 Subtractive++; 693 } while (TempQword != 0); 694 695 if (Positive <= Subtractive) { 696 *MtrrNumber += Positive; 697 return TRUE; 698 } else { 699 *MtrrNumber += Subtractive; 700 return FALSE; 701 } 702} 703 704/** 705 Invalid variable MTRRs according to the value in the shadow array. 706 707 This function programs MTRRs according to the values specified 708 in the shadow array. 709 710 @param VariableMtrr The array to shadow variable MTRRs content 711 712**/ 713VOID 714InvalidateMtrr ( 715 IN VARIABLE_MTRR *VariableMtrr 716 ) 717{ 718 UINTN Index; 719 UINTN VariableMtrrCount; 720 MTRR_CONTEXT MtrrContext; 721 722 PreMtrrChange (&MtrrContext); 723 Index = 0; 724 VariableMtrrCount = GetVariableMtrrCount (); 725 while (Index < VariableMtrrCount) { 726 if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) { 727 AsmWriteMsr64 (VariableMtrr[Index].Msr, 0); 728 AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0); 729 VariableMtrr[Index].Used = FALSE; 730 } 731 Index ++; 732 } 733 PostMtrrChange (&MtrrContext); 734} 735 736 737/** 738 Programs variable MTRRs 739 740 This function programs variable MTRRs 741 742 @param MtrrNumber Index of MTRR to program. 743 @param BaseAddress Base address of memory region. 744 @param Length Length of memory region. 745 @param MemoryCacheType Memory type to set. 746 @param MtrrValidAddressMask The valid address mask for MTRR 747 748**/ 749VOID 750ProgramVariableMtrr ( 751 IN UINTN MtrrNumber, 752 IN PHYSICAL_ADDRESS BaseAddress, 753 IN UINT64 Length, 754 IN UINT64 MemoryCacheType, 755 IN UINT64 MtrrValidAddressMask 756 ) 757{ 758 UINT64 TempQword; 759 MTRR_CONTEXT MtrrContext; 760 761 PreMtrrChange (&MtrrContext); 762 763 // 764 // MTRR Physical Base 765 // 766 TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType; 767 AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword); 768 769 // 770 // MTRR Physical Mask 771 // 772 TempQword = ~(Length - 1); 773 AsmWriteMsr64 ( 774 (UINT32) (MtrrNumber + 1), 775 (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED 776 ); 777 778 PostMtrrChange (&MtrrContext); 779} 780 781 782/** 783 Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE. 784 785 @param MtrrType MTRR memory type 786 787 @return The enum item in MTRR_MEMORY_CACHE_TYPE 788 789**/ 790MTRR_MEMORY_CACHE_TYPE 791GetMemoryCacheTypeFromMtrrType ( 792 IN UINT64 MtrrType 793 ) 794{ 795 switch (MtrrType) { 796 case MTRR_CACHE_UNCACHEABLE: 797 return CacheUncacheable; 798 case MTRR_CACHE_WRITE_COMBINING: 799 return CacheWriteCombining; 800 case MTRR_CACHE_WRITE_THROUGH: 801 return CacheWriteThrough; 802 case MTRR_CACHE_WRITE_PROTECTED: 803 return CacheWriteProtected; 804 case MTRR_CACHE_WRITE_BACK: 805 return CacheWriteBack; 806 default: 807 // 808 // MtrrType is MTRR_CACHE_INVALID_TYPE, that means 809 // no mtrr covers the range 810 // 811 return CacheUncacheable; 812 } 813} 814 815/** 816 Initializes the valid bits mask and valid address mask for MTRRs. 817 818 This function initializes the valid bits mask and valid address mask for MTRRs. 819 820 @param MtrrValidBitsMask The mask for the valid bit of the MTRR 821 @param MtrrValidAddressMask The valid address mask for the MTRR 822 823**/ 824VOID 825MtrrLibInitializeMtrrMask ( 826 OUT UINT64 *MtrrValidBitsMask, 827 OUT UINT64 *MtrrValidAddressMask 828 ) 829{ 830 UINT32 RegEax; 831 UINT8 PhysicalAddressBits; 832 833 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); 834 835 if (RegEax >= 0x80000008) { 836 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); 837 838 PhysicalAddressBits = (UINT8) RegEax; 839 840 *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; 841 *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL; 842 } else { 843 *MtrrValidBitsMask = MTRR_LIB_CACHE_VALID_ADDRESS; 844 *MtrrValidAddressMask = 0xFFFFFFFF; 845 } 846} 847 848 849/** 850 Determing the real attribute of a memory range. 851 852 This function is to arbitrate the real attribute of the memory when 853 there are 2 MTRR covers the same memory range. For further details, 854 please refer the IA32 Software Developer's Manual, Volume 3, 855 Section 10.11.4.1. 856 857 @param MtrrType1 the first kind of Memory type 858 @param MtrrType2 the second kind of memory type 859 860**/ 861UINT64 862MtrrPrecedence ( 863 UINT64 MtrrType1, 864 UINT64 MtrrType2 865 ) 866{ 867 UINT64 MtrrType; 868 869 MtrrType = MTRR_CACHE_INVALID_TYPE; 870 switch (MtrrType1) { 871 case MTRR_CACHE_UNCACHEABLE: 872 MtrrType = MTRR_CACHE_UNCACHEABLE; 873 break; 874 case MTRR_CACHE_WRITE_COMBINING: 875 if ( 876 MtrrType2==MTRR_CACHE_WRITE_COMBINING || 877 MtrrType2==MTRR_CACHE_UNCACHEABLE 878 ) { 879 MtrrType = MtrrType2; 880 } 881 break; 882 case MTRR_CACHE_WRITE_THROUGH: 883 if ( 884 MtrrType2==MTRR_CACHE_WRITE_THROUGH || 885 MtrrType2==MTRR_CACHE_WRITE_BACK 886 ) { 887 MtrrType = MTRR_CACHE_WRITE_THROUGH; 888 } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) { 889 MtrrType = MTRR_CACHE_UNCACHEABLE; 890 } 891 break; 892 case MTRR_CACHE_WRITE_PROTECTED: 893 if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED || 894 MtrrType2 == MTRR_CACHE_UNCACHEABLE) { 895 MtrrType = MtrrType2; 896 } 897 break; 898 case MTRR_CACHE_WRITE_BACK: 899 if ( 900 MtrrType2== MTRR_CACHE_UNCACHEABLE || 901 MtrrType2==MTRR_CACHE_WRITE_THROUGH || 902 MtrrType2== MTRR_CACHE_WRITE_BACK 903 ) { 904 MtrrType = MtrrType2; 905 } 906 break; 907 case MTRR_CACHE_INVALID_TYPE: 908 MtrrType = MtrrType2; 909 break; 910 default: 911 break; 912 } 913 914 if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) { 915 MtrrType = MtrrType1; 916 } 917 return MtrrType; 918} 919 920 921/** 922 This function attempts to set the attributes for a memory range. 923 924 @param BaseAddress The physical address that is the start 925 address of a memory region. 926 @param Length The size in bytes of the memory region. 927 @param Attributes The bit mask of attributes to set for the 928 memory region. 929 930 @retval RETURN_SUCCESS The attributes were set for the memory 931 region. 932 @retval RETURN_INVALID_PARAMETER Length is zero. 933 @retval RETURN_UNSUPPORTED The processor does not support one or 934 more bytes of the memory resource range 935 specified by BaseAddress and Length. 936 @retval RETURN_UNSUPPORTED The bit mask of attributes is not support 937 for the memory resource range specified 938 by BaseAddress and Length. 939 @retval RETURN_ACCESS_DENIED The attributes for the memory resource 940 range specified by BaseAddress and Length 941 cannot be modified. 942 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to 943 modify the attributes of the memory 944 resource range. 945 946**/ 947RETURN_STATUS 948EFIAPI 949MtrrSetMemoryAttribute ( 950 IN PHYSICAL_ADDRESS BaseAddress, 951 IN UINT64 Length, 952 IN MTRR_MEMORY_CACHE_TYPE Attribute 953 ) 954{ 955 UINT64 TempQword; 956 RETURN_STATUS Status; 957 UINT64 MemoryType; 958 UINT64 Alignment; 959 BOOLEAN OverLap; 960 BOOLEAN Positive; 961 UINT32 MsrNum; 962 UINTN MtrrNumber; 963 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; 964 UINT32 UsedMtrr; 965 UINT64 MtrrValidBitsMask; 966 UINT64 MtrrValidAddressMask; 967 BOOLEAN OverwriteExistingMtrr; 968 UINT32 FirmwareVariableMtrrCount; 969 UINT32 VariableMtrrEnd; 970 MTRR_CONTEXT MtrrContext; 971 972 DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); 973 974 if (!IsMtrrSupported ()) { 975 Status = RETURN_UNSUPPORTED; 976 goto Done; 977 } 978 979 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); 980 VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; 981 982 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); 983 984 TempQword = 0; 985 MemoryType = (UINT64)Attribute; 986 OverwriteExistingMtrr = FALSE; 987 988 // 989 // Check for an invalid parameter 990 // 991 if (Length == 0) { 992 Status = RETURN_INVALID_PARAMETER; 993 goto Done; 994 } 995 996 if ( 997 (BaseAddress & ~MtrrValidAddressMask) != 0 || 998 (Length & ~MtrrValidAddressMask) != 0 999 ) { 1000 Status = RETURN_UNSUPPORTED; 1001 goto Done; 1002 } 1003 1004 // 1005 // Check if Fixed MTRR 1006 // 1007 Status = RETURN_SUCCESS; 1008 while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { 1009 PreMtrrChange (&MtrrContext); 1010 Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length); 1011 PostMtrrChange (&MtrrContext); 1012 if (RETURN_ERROR (Status)) { 1013 goto Done; 1014 } 1015 } 1016 1017 if (Length == 0) { 1018 // 1019 // A Length of 0 can only make sense for fixed MTTR ranges. 1020 // Since we just handled the fixed MTRRs, we can skip the 1021 // variable MTRR section. 1022 // 1023 goto Done; 1024 } 1025 1026 // 1027 // Since memory ranges below 1MB will be overridden by the fixed MTRRs, 1028 // we can set the base to 0 to save variable MTRRs. 1029 // 1030 if (BaseAddress == BASE_1MB) { 1031 BaseAddress = 0; 1032 Length += SIZE_1MB; 1033 } 1034 1035 // 1036 // Check for overlap 1037 // 1038 UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); 1039 OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr); 1040 if (OverLap) { 1041 Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr); 1042 if (RETURN_ERROR (Status)) { 1043 goto Done; 1044 } 1045 1046 if (Length == 0) { 1047 // 1048 // Combined successfully, invalidate the now-unused MTRRs 1049 // 1050 InvalidateMtrr(VariableMtrr); 1051 Status = RETURN_SUCCESS; 1052 goto Done; 1053 } 1054 } 1055 1056 // 1057 // The memory type is the same with the type specified by 1058 // MTRR_LIB_IA32_MTRR_DEF_TYPE. 1059 // 1060 if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) { 1061 // 1062 // Invalidate the now-unused MTRRs 1063 // 1064 InvalidateMtrr(VariableMtrr); 1065 goto Done; 1066 } 1067 1068 Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber); 1069 1070 if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) { 1071 Status = RETURN_OUT_OF_RESOURCES; 1072 goto Done; 1073 } 1074 1075 // 1076 // Invalidate the now-unused MTRRs 1077 // 1078 InvalidateMtrr(VariableMtrr); 1079 1080 // 1081 // Find first unused MTRR 1082 // 1083 for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE; 1084 MsrNum < VariableMtrrEnd; 1085 MsrNum += 2 1086 ) { 1087 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { 1088 break; 1089 } 1090 } 1091 1092 if (BaseAddress != 0) { 1093 do { 1094 // 1095 // Calculate the alignment of the base address. 1096 // 1097 Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); 1098 1099 if (Alignment > Length) { 1100 break; 1101 } 1102 1103 // 1104 // Find unused MTRR 1105 // 1106 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { 1107 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { 1108 break; 1109 } 1110 } 1111 1112 ProgramVariableMtrr ( 1113 MsrNum, 1114 BaseAddress, 1115 Alignment, 1116 MemoryType, 1117 MtrrValidAddressMask 1118 ); 1119 BaseAddress += Alignment; 1120 Length -= Alignment; 1121 } while (TRUE); 1122 1123 if (Length == 0) { 1124 goto Done; 1125 } 1126 } 1127 1128 TempQword = Length; 1129 1130 if (!Positive) { 1131 Length = Power2MaxMemory (LShiftU64 (TempQword, 1)); 1132 1133 // 1134 // Find unused MTRR 1135 // 1136 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { 1137 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { 1138 break; 1139 } 1140 } 1141 1142 ProgramVariableMtrr ( 1143 MsrNum, 1144 BaseAddress, 1145 Length, 1146 MemoryType, 1147 MtrrValidAddressMask 1148 ); 1149 BaseAddress += Length; 1150 TempQword = Length - TempQword; 1151 MemoryType = MTRR_CACHE_UNCACHEABLE; 1152 } 1153 1154 do { 1155 // 1156 // Find unused MTRR 1157 // 1158 for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { 1159 if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { 1160 break; 1161 } 1162 } 1163 1164 Length = Power2MaxMemory (TempQword); 1165 if (!Positive) { 1166 BaseAddress -= Length; 1167 } 1168 1169 ProgramVariableMtrr ( 1170 MsrNum, 1171 BaseAddress, 1172 Length, 1173 MemoryType, 1174 MtrrValidAddressMask 1175 ); 1176 1177 if (Positive) { 1178 BaseAddress += Length; 1179 } 1180 TempQword -= Length; 1181 1182 } while (TempQword > 0); 1183 1184Done: 1185 DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); 1186 if (!RETURN_ERROR (Status)) { 1187 MtrrDebugPrintAllMtrrs (); 1188 } 1189 1190 return Status; 1191} 1192 1193 1194/** 1195 This function will get the memory cache type of the specific address. 1196 1197 This function is mainly for debug purpose. 1198 1199 @param Address The specific address 1200 1201 @return Memory cache type of the sepcific address 1202 1203**/ 1204MTRR_MEMORY_CACHE_TYPE 1205EFIAPI 1206MtrrGetMemoryAttribute ( 1207 IN PHYSICAL_ADDRESS Address 1208 ) 1209{ 1210 UINT64 TempQword; 1211 UINTN Index; 1212 UINTN SubIndex; 1213 UINT64 MtrrType; 1214 UINT64 TempMtrrType; 1215 MTRR_MEMORY_CACHE_TYPE CacheType; 1216 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; 1217 UINT64 MtrrValidBitsMask; 1218 UINT64 MtrrValidAddressMask; 1219 UINTN VariableMtrrCount; 1220 1221 if (!IsMtrrSupported ()) { 1222 return CacheUncacheable; 1223 } 1224 1225 // 1226 // Check if MTRR is enabled, if not, return UC as attribute 1227 // 1228 TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); 1229 MtrrType = MTRR_CACHE_INVALID_TYPE; 1230 1231 if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { 1232 return CacheUncacheable; 1233 } 1234 1235 // 1236 // If address is less than 1M, then try to go through the fixed MTRR 1237 // 1238 if (Address < BASE_1MB) { 1239 if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) { 1240 // 1241 // Go through the fixed MTRR 1242 // 1243 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { 1244 if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress && 1245 Address < ( 1246 mMtrrLibFixedMtrrTable[Index].BaseAddress + 1247 (mMtrrLibFixedMtrrTable[Index].Length * 8) 1248 ) 1249 ) { 1250 SubIndex = 1251 ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) / 1252 mMtrrLibFixedMtrrTable[Index].Length; 1253 TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); 1254 MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF; 1255 return GetMemoryCacheTypeFromMtrrType (MtrrType); 1256 } 1257 } 1258 } 1259 } 1260 MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); 1261 MtrrGetMemoryAttributeInVariableMtrr( 1262 MtrrValidBitsMask, 1263 MtrrValidAddressMask, 1264 VariableMtrr 1265 ); 1266 1267 // 1268 // Go through the variable MTRR 1269 // 1270 VariableMtrrCount = GetVariableMtrrCount (); 1271 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); 1272 1273 for (Index = 0; Index < VariableMtrrCount; Index++) { 1274 if (VariableMtrr[Index].Valid) { 1275 if (Address >= VariableMtrr[Index].BaseAddress && 1276 Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) { 1277 TempMtrrType = VariableMtrr[Index].Type; 1278 MtrrType = MtrrPrecedence (MtrrType, TempMtrrType); 1279 } 1280 } 1281 } 1282 CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType); 1283 1284 return CacheType; 1285} 1286 1287 1288/** 1289 This function will get the raw value in variable MTRRs 1290 1291 @param VariableSettings A buffer to hold variable MTRRs content. 1292 1293 @return The VariableSettings input pointer 1294 1295**/ 1296MTRR_VARIABLE_SETTINGS* 1297EFIAPI 1298MtrrGetVariableMtrr ( 1299 OUT MTRR_VARIABLE_SETTINGS *VariableSettings 1300 ) 1301{ 1302 UINT32 Index; 1303 UINT32 VariableMtrrCount; 1304 1305 if (!IsMtrrSupported ()) { 1306 return VariableSettings; 1307 } 1308 1309 VariableMtrrCount = GetVariableMtrrCount (); 1310 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); 1311 1312 for (Index = 0; Index < VariableMtrrCount; Index++) { 1313 VariableSettings->Mtrr[Index].Base = 1314 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1)); 1315 VariableSettings->Mtrr[Index].Mask = 1316 AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1); 1317 } 1318 1319 return VariableSettings; 1320} 1321 1322 1323/** 1324 Worker function setting variable MTRRs 1325 1326 @param VariableSettings A buffer to hold variable MTRRs content. 1327 1328**/ 1329VOID 1330MtrrSetVariableMtrrWorker ( 1331 IN MTRR_VARIABLE_SETTINGS *VariableSettings 1332 ) 1333{ 1334 UINT32 Index; 1335 UINT32 VariableMtrrCount; 1336 1337 VariableMtrrCount = GetVariableMtrrCount (); 1338 ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR); 1339 1340 for (Index = 0; Index < VariableMtrrCount; Index++) { 1341 AsmWriteMsr64 ( 1342 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1), 1343 VariableSettings->Mtrr[Index].Base 1344 ); 1345 AsmWriteMsr64 ( 1346 MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1, 1347 VariableSettings->Mtrr[Index].Mask 1348 ); 1349 } 1350} 1351 1352 1353/** 1354 This function sets variable MTRRs 1355 1356 @param VariableSettings A buffer to hold variable MTRRs content. 1357 1358 @return The pointer of VariableSettings 1359 1360**/ 1361MTRR_VARIABLE_SETTINGS* 1362EFIAPI 1363MtrrSetVariableMtrr ( 1364 IN MTRR_VARIABLE_SETTINGS *VariableSettings 1365 ) 1366{ 1367 MTRR_CONTEXT MtrrContext; 1368 1369 if (!IsMtrrSupported ()) { 1370 return VariableSettings; 1371 } 1372 1373 PreMtrrChange (&MtrrContext); 1374 MtrrSetVariableMtrrWorker (VariableSettings); 1375 PostMtrrChange (&MtrrContext); 1376 return VariableSettings; 1377} 1378 1379 1380/** 1381 This function gets the content in fixed MTRRs 1382 1383 @param FixedSettings A buffer to hold fixed Mtrrs content. 1384 1385 @retval The pointer of FixedSettings 1386 1387**/ 1388MTRR_FIXED_SETTINGS* 1389EFIAPI 1390MtrrGetFixedMtrr ( 1391 OUT MTRR_FIXED_SETTINGS *FixedSettings 1392 ) 1393{ 1394 UINT32 Index; 1395 1396 if (!IsMtrrSupported ()) { 1397 return FixedSettings; 1398 } 1399 1400 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { 1401 FixedSettings->Mtrr[Index] = 1402 AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr); 1403 }; 1404 1405 return FixedSettings; 1406} 1407 1408/** 1409 Worker function setting fixed MTRRs 1410 1411 @param FixedSettings A buffer to hold fixed Mtrrs content. 1412 1413**/ 1414VOID 1415MtrrSetFixedMtrrWorker ( 1416 IN MTRR_FIXED_SETTINGS *FixedSettings 1417 ) 1418{ 1419 UINT32 Index; 1420 1421 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { 1422 AsmWriteMsr64 ( 1423 mMtrrLibFixedMtrrTable[Index].Msr, 1424 FixedSettings->Mtrr[Index] 1425 ); 1426 } 1427} 1428 1429 1430/** 1431 This function sets fixed MTRRs 1432 1433 @param FixedSettings A buffer to hold fixed Mtrrs content. 1434 1435 @retval The pointer of FixedSettings 1436 1437**/ 1438MTRR_FIXED_SETTINGS* 1439EFIAPI 1440MtrrSetFixedMtrr ( 1441 IN MTRR_FIXED_SETTINGS *FixedSettings 1442 ) 1443{ 1444 MTRR_CONTEXT MtrrContext; 1445 1446 if (!IsMtrrSupported ()) { 1447 return FixedSettings; 1448 } 1449 1450 PreMtrrChange (&MtrrContext); 1451 MtrrSetFixedMtrrWorker (FixedSettings); 1452 PostMtrrChange (&MtrrContext); 1453 1454 return FixedSettings; 1455} 1456 1457 1458/** 1459 This function gets the content in all MTRRs (variable and fixed) 1460 1461 @param MtrrSetting A buffer to hold all Mtrrs content. 1462 1463 @retval the pointer of MtrrSetting 1464 1465**/ 1466MTRR_SETTINGS * 1467EFIAPI 1468MtrrGetAllMtrrs ( 1469 OUT MTRR_SETTINGS *MtrrSetting 1470 ) 1471{ 1472 if (!IsMtrrSupported ()) { 1473 return MtrrSetting; 1474 } 1475 1476 // 1477 // Get fixed MTRRs 1478 // 1479 MtrrGetFixedMtrr (&MtrrSetting->Fixed); 1480 1481 // 1482 // Get variable MTRRs 1483 // 1484 MtrrGetVariableMtrr (&MtrrSetting->Variables); 1485 1486 // 1487 // Get MTRR_DEF_TYPE value 1488 // 1489 MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE); 1490 1491 return MtrrSetting; 1492} 1493 1494 1495/** 1496 This function sets all MTRRs (variable and fixed) 1497 1498 @param MtrrSetting A buffer holding all MTRRs content. 1499 1500 @retval The pointer of MtrrSetting 1501 1502**/ 1503MTRR_SETTINGS * 1504EFIAPI 1505MtrrSetAllMtrrs ( 1506 IN MTRR_SETTINGS *MtrrSetting 1507 ) 1508{ 1509 MTRR_CONTEXT MtrrContext; 1510 1511 if (!IsMtrrSupported ()) { 1512 return MtrrSetting; 1513 } 1514 1515 PreMtrrChange (&MtrrContext); 1516 1517 // 1518 // Set fixed MTRRs 1519 // 1520 MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed); 1521 1522 // 1523 // Set variable MTRRs 1524 // 1525 MtrrSetVariableMtrrWorker (&MtrrSetting->Variables); 1526 1527 // 1528 // Set MTRR_DEF_TYPE value 1529 // 1530 AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType); 1531 1532 PostMtrrChangeEnableCache (&MtrrContext); 1533 1534 return MtrrSetting; 1535} 1536 1537/** 1538 This function prints all MTRRs for debugging. 1539**/ 1540VOID 1541EFIAPI 1542MtrrDebugPrintAllMtrrs ( 1543 VOID 1544 ) 1545{ 1546 DEBUG_CODE ( 1547 MTRR_SETTINGS MtrrSettings; 1548 UINTN Index; 1549 UINTN Index1; 1550 UINTN VariableMtrrCount; 1551 UINT64 Base; 1552 UINT64 Limit; 1553 UINT64 MtrrBase; 1554 UINT64 MtrrLimit; 1555 UINT64 RangeBase; 1556 UINT64 RangeLimit; 1557 UINT64 NoRangeBase; 1558 UINT64 NoRangeLimit; 1559 UINT32 RegEax; 1560 UINTN MemoryType; 1561 UINTN PreviousMemoryType; 1562 BOOLEAN Found; 1563 1564 if (!IsMtrrSupported ()) { 1565 return; 1566 } 1567 1568 DEBUG((DEBUG_CACHE, "MTRR Settings\n")); 1569 DEBUG((DEBUG_CACHE, "=============\n")); 1570 1571 MtrrGetAllMtrrs (&MtrrSettings); 1572 DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", MtrrSettings.MtrrDefType)); 1573 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { 1574 DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, MtrrSettings.Fixed.Mtrr[Index])); 1575 } 1576 1577 VariableMtrrCount = GetVariableMtrrCount (); 1578 for (Index = 0; Index < VariableMtrrCount; Index++) { 1579 DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n", 1580 Index, 1581 MtrrSettings.Variables.Mtrr[Index].Base, 1582 MtrrSettings.Variables.Mtrr[Index].Mask 1583 )); 1584 } 1585 DEBUG((DEBUG_CACHE, "\n")); 1586 DEBUG((DEBUG_CACHE, "MTRR Ranges\n")); 1587 DEBUG((DEBUG_CACHE, "====================================\n")); 1588 1589 Base = 0; 1590 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; 1591 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) { 1592 Base = mMtrrLibFixedMtrrTable[Index].BaseAddress; 1593 for (Index1 = 0; Index1 < 8; Index1++) { 1594 MemoryType = (UINTN)(RShiftU64 (MtrrSettings.Fixed.Mtrr[Index], Index1 * 8) & 0xff); 1595 if (MemoryType > CacheWriteBack) { 1596 MemoryType = MTRR_CACHE_INVALID_TYPE; 1597 } 1598 if (MemoryType != PreviousMemoryType) { 1599 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { 1600 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); 1601 } 1602 PreviousMemoryType = MemoryType; 1603 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); 1604 } 1605 Base += mMtrrLibFixedMtrrTable[Index].Length; 1606 } 1607 } 1608 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); 1609 1610 VariableMtrrCount = GetVariableMtrrCount (); 1611 1612 Base = BASE_1MB; 1613 PreviousMemoryType = MTRR_CACHE_INVALID_TYPE; 1614 do { 1615 MemoryType = MtrrGetMemoryAttribute (Base); 1616 if (MemoryType > CacheWriteBack) { 1617 MemoryType = MTRR_CACHE_INVALID_TYPE; 1618 } 1619 1620 if (MemoryType != PreviousMemoryType) { 1621 if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) { 1622 DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1)); 1623 } 1624 PreviousMemoryType = MemoryType; 1625 DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base)); 1626 } 1627 1628 RangeBase = BASE_1MB; 1629 NoRangeBase = BASE_1MB; 1630 Limit = BIT36 - 1; 1631 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); 1632 if (RegEax >= 0x80000008) { 1633 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); 1634 Limit = LShiftU64 (1, RegEax & 0xff) - 1; 1635 } 1636 RangeLimit = Limit; 1637 NoRangeLimit = Limit; 1638 1639 for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) { 1640 if ((MtrrSettings.Variables.Mtrr[Index].Mask & BIT11) == 0) { 1641 // 1642 // If mask is not valid, then do not display range 1643 // 1644 continue; 1645 } 1646 MtrrBase = (MtrrSettings.Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1))); 1647 MtrrLimit = MtrrBase + ((~(MtrrSettings.Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit); 1648 1649 if (Base >= MtrrBase && Base < MtrrLimit) { 1650 Found = TRUE; 1651 } 1652 1653 if (Base >= MtrrBase && MtrrBase > RangeBase) { 1654 RangeBase = MtrrBase; 1655 } 1656 if (Base > MtrrLimit && MtrrLimit > RangeBase) { 1657 RangeBase = MtrrLimit + 1; 1658 } 1659 if (Base < MtrrBase && MtrrBase < RangeLimit) { 1660 RangeLimit = MtrrBase - 1; 1661 } 1662 if (Base < MtrrLimit && MtrrLimit <= RangeLimit) { 1663 RangeLimit = MtrrLimit; 1664 } 1665 1666 if (Base > MtrrLimit && NoRangeBase < MtrrLimit) { 1667 NoRangeBase = MtrrLimit + 1; 1668 } 1669 if (Base < MtrrBase && NoRangeLimit > MtrrBase) { 1670 NoRangeLimit = MtrrBase - 1; 1671 } 1672 } 1673 1674 if (Found) { 1675 Base = RangeLimit + 1; 1676 } else { 1677 Base = NoRangeLimit + 1; 1678 } 1679 } while (Found); 1680 DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1)); 1681 ); 1682} 1683 1684/** 1685 Checks if MTRR is supported. 1686 1687 @retval TRUE MTRR is supported. 1688 @retval FALSE MTRR is not supported. 1689 1690**/ 1691BOOLEAN 1692EFIAPI 1693IsMtrrSupported ( 1694 VOID 1695 ) 1696{ 1697 UINT32 RegEdx; 1698 UINT64 MtrrCap; 1699 1700 // 1701 // Check CPUID(1).EDX[12] for MTRR capability 1702 // 1703 AsmCpuid (1, NULL, NULL, NULL, &RegEdx); 1704 if (BitFieldRead32 (RegEdx, 12, 12) == 0) { 1705 return FALSE; 1706 } 1707 1708 // 1709 // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for 1710 // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not 1711 // exist, return false. 1712 // 1713 MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP); 1714 if ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) { 1715 return FALSE; 1716 } 1717 1718 return TRUE; 1719} 1720