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