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