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