/** Programs variable MTRRs This function programs variable MTRRs @param MtrrNumber Index of MTRR to program. @param BaseAddress Base address of memory region. @param Length Length of memory region. @param MemoryCacheType Memory type to set. @param MtrrValidAddressMask The valid address mask for MTRR **/ VOID ProgramVariableMtrr ( IN UINTN MtrrNumber, IN PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 MemoryCacheType, IN UINT64 MtrrValidAddressMask ) { UINT64 TempQword; MTRR_CONTEXT MtrrContext; PreMtrrChange (&MtrrContext); // // MTRR Physical Base // TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType; AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword); // // MTRR Physical Mask // TempQword = ~(Length - 1); AsmWriteMsr64 ( (UINT32) (MtrrNumber + 1), (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED ); PostMtrrChange (&MtrrContext); }
EFIAPI MtrrSetAllMtrrs ( IN MTRR_SETTINGS *MtrrSetting ) { MTRR_CONTEXT MtrrContext; if (!IsMtrrSupported ()) { return MtrrSetting; } PreMtrrChange (&MtrrContext); // // Set fixed MTRRs // MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed); // // Set variable MTRRs // MtrrSetVariableMtrrWorker (&MtrrSetting->Variables); // // Set MTRR_DEF_TYPE value // AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType); PostMtrrChangeEnableCache (&MtrrContext); return MtrrSetting; }
EFIAPI MtrrSetAllMtrrs ( IN MTRR_SETTINGS *MtrrSetting ) { UINTN Cr4; if (!IsMtrrSupported ()) { return MtrrSetting; } Cr4 = PreMtrrChange (); // // Set fixed MTRRs // MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed); // // Set variable MTRRs // MtrrSetVariableMtrrWorker (&MtrrSetting->Variables); // // Set MTRR_DEF_TYPE value // AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType); PostMtrrChange (Cr4); return MtrrSetting; }
EFIAPI MtrrSetVariableMtrr ( IN MTRR_VARIABLE_SETTINGS *VariableSettings ) { MTRR_CONTEXT MtrrContext; if (!IsMtrrSupported ()) { return VariableSettings; } PreMtrrChange (&MtrrContext); MtrrSetVariableMtrrWorker (VariableSettings); PostMtrrChange (&MtrrContext); return VariableSettings; }
EFIAPI MtrrSetVariableMtrr ( IN MTRR_VARIABLE_SETTINGS *VariableSettings ) { UINTN Cr4; if (!IsMtrrSupported ()) { return VariableSettings; } Cr4 = PreMtrrChange (); MtrrSetVariableMtrrWorker (VariableSettings); PostMtrrChange (Cr4); return VariableSettings; }
EFIAPI MtrrSetFixedMtrr ( IN MTRR_FIXED_SETTINGS *FixedSettings ) { MTRR_CONTEXT MtrrContext; if (!IsMtrrSupported ()) { return FixedSettings; } PreMtrrChange (&MtrrContext); MtrrSetFixedMtrrWorker (FixedSettings); PostMtrrChange (&MtrrContext); return FixedSettings; }
EFIAPI MtrrSetFixedMtrr ( IN MTRR_FIXED_SETTINGS *FixedSettings ) { UINTN Cr4; if (!IsMtrrSupported ()) { return FixedSettings; } Cr4 = PreMtrrChange (); MtrrSetFixedMtrrWorker (FixedSettings); PostMtrrChange (Cr4); return FixedSettings; }
/** Invalid variable MTRRs according to the value in the shadow array. This function programs MTRRs according to the values specified in the shadow array. @param VariableMtrr The array to shadow variable MTRRs content **/ VOID InvalidateMtrr ( IN VARIABLE_MTRR *VariableMtrr ) { UINTN Index; UINTN VariableMtrrCount; MTRR_CONTEXT MtrrContext; PreMtrrChange (&MtrrContext); Index = 0; VariableMtrrCount = GetVariableMtrrCount (); while (Index < VariableMtrrCount) { if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) { AsmWriteMsr64 (VariableMtrr[Index].Msr, 0); AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0); VariableMtrr[Index].Used = FALSE; } Index ++; } PostMtrrChange (&MtrrContext); }
/** Invalid variable MTRRs according to the value in the shadow array. This function programs MTRRs according to the values specified in the shadow array. @param VariableMtrr The array to shadow variable MTRRs content **/ STATIC VOID InvalidateMtrr ( IN VARIABLE_MTRR *VariableMtrr ) { UINTN Index; UINTN Cr4; UINTN VariableMtrrCount; Cr4 = PreMtrrChange (); Index = 0; VariableMtrrCount = GetVariableMtrrCount (); while (Index < VariableMtrrCount) { if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) { AsmWriteMsr64 (VariableMtrr[Index].Msr, 0); AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0); VariableMtrr[Index].Used = FALSE; } Index ++; } PostMtrrChange (Cr4); }
/** This function attempts to set the attributes for a memory range. @param BaseAddress The physical address that is the start address of a memory region. @param Length The size in bytes of the memory region. @param Attributes The bit mask of attributes to set for the memory region. @retval RETURN_SUCCESS The attributes were set for the memory region. @retval RETURN_INVALID_PARAMETER Length is zero. @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory resource range specified by BaseAddress and Length. @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource range specified by BaseAddress and Length. @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by BaseAddress and Length cannot be modified. @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of the memory resource range. **/ RETURN_STATUS EFIAPI MtrrSetMemoryAttribute ( IN PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN MTRR_MEMORY_CACHE_TYPE Attribute ) { UINT64 TempQword; RETURN_STATUS Status; UINT64 MemoryType; UINT64 Alignment; BOOLEAN OverLap; BOOLEAN Positive; UINT32 MsrNum; UINTN MtrrNumber; VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; UINT32 UsedMtrr; UINT64 MtrrValidBitsMask; UINT64 MtrrValidAddressMask; BOOLEAN OverwriteExistingMtrr; UINT32 FirmwareVariableMtrrCount; UINT32 VariableMtrrEnd; MTRR_CONTEXT MtrrContext; DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length)); if (!IsMtrrSupported ()) { Status = RETURN_UNSUPPORTED; goto Done; } FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); TempQword = 0; MemoryType = (UINT64)Attribute; OverwriteExistingMtrr = FALSE; // // Check for an invalid parameter // if (Length == 0) { Status = RETURN_INVALID_PARAMETER; goto Done; } if ( (BaseAddress & ~MtrrValidAddressMask) != 0 || (Length & ~MtrrValidAddressMask) != 0 ) { Status = RETURN_UNSUPPORTED; goto Done; } // // Check if Fixed MTRR // Status = RETURN_SUCCESS; while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { PreMtrrChange (&MtrrContext); Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length); PostMtrrChange (&MtrrContext); if (RETURN_ERROR (Status)) { goto Done; } } if (Length == 0) { // // A Length of 0 can only make sense for fixed MTTR ranges. // Since we just handled the fixed MTRRs, we can skip the // variable MTRR section. // goto Done; } // // Since memory ranges below 1MB will be overridden by the fixed MTRRs, // we can set the base to 0 to save variable MTRRs. // if (BaseAddress == BASE_1MB) { BaseAddress = 0; Length += SIZE_1MB; } // // Check for overlap // UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr); if (OverLap) { Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr); if (RETURN_ERROR (Status)) { goto Done; } if (Length == 0) { // // Combined successfully, invalidate the now-unused MTRRs // InvalidateMtrr(VariableMtrr); Status = RETURN_SUCCESS; goto Done; } } // // The memory type is the same with the type specified by // MTRR_LIB_IA32_MTRR_DEF_TYPE. // if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) { // // Invalidate the now-unused MTRRs // InvalidateMtrr(VariableMtrr); goto Done; } Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber); if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) { Status = RETURN_OUT_OF_RESOURCES; goto Done; } // // Invalidate the now-unused MTRRs // InvalidateMtrr(VariableMtrr); // // Find first unused MTRR // for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE; MsrNum < VariableMtrrEnd; MsrNum += 2 ) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } if (BaseAddress != 0) { do { // // Calculate the alignment of the base address. // Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress)); if (Alignment > Length) { break; } // // Find unused MTRR // for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } ProgramVariableMtrr ( MsrNum, BaseAddress, Alignment, MemoryType, MtrrValidAddressMask ); BaseAddress += Alignment; Length -= Alignment; } while (TRUE); if (Length == 0) { goto Done; } } TempQword = Length; if (!Positive) { Length = Power2MaxMemory (LShiftU64 (TempQword, 1)); // // Find unused MTRR // for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } ProgramVariableMtrr ( MsrNum, BaseAddress, Length, MemoryType, MtrrValidAddressMask ); BaseAddress += Length; TempQword = Length - TempQword; MemoryType = MTRR_CACHE_UNCACHEABLE; } do { // // Find unused MTRR // for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } Length = Power2MaxMemory (TempQword); if (!Positive) { BaseAddress -= Length; } ProgramVariableMtrr ( MsrNum, BaseAddress, Length, MemoryType, MtrrValidAddressMask ); if (Positive) { BaseAddress += Length; } TempQword -= Length; } while (TempQword > 0); Done: DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); if (!RETURN_ERROR (Status)) { MtrrDebugPrintAllMtrrs (); } return Status; }
/** This function attempts to set the attributes for a memory range. @param BaseAddress The physical address that is the start address of a memory region. @param Length The size in bytes of the memory region. @param Attributes The bit mask of attributes to set for the memory region. @retval RETURN_SUCCESS The attributes were set for the memory region. @retval RETURN_INVALID_PARAMETER Length is zero. @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory resource range specified by BaseAddress and Length. @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource range specified by BaseAddress and Length. @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by BaseAddress and Length cannot be modified. @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of the memory resource range. **/ RETURN_STATUS EFIAPI MtrrSetMemoryAttribute ( IN PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN MTRR_MEMORY_CACHE_TYPE Attribute ) { UINT64 TempQword; RETURN_STATUS Status; UINT64 MemoryType; UINT64 Remainder; BOOLEAN OverLap; BOOLEAN Positive; UINT32 MsrNum; UINTN MtrrNumber; VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; UINT32 UsedMtrr; UINT64 MtrrValidBitsMask; UINT64 MtrrValidAddressMask; UINTN Cr4; BOOLEAN OverwriteExistingMtrr; UINT32 FirmwareVariableMtrrCount; UINT32 VariableMtrrEnd; if (!IsMtrrSupported ()) { return RETURN_UNSUPPORTED; } FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount (); VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1; MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask); TempQword = 0; MemoryType = (UINT64)Attribute; OverwriteExistingMtrr = FALSE; // // Check for an invalid parameter // if (Length == 0) { return RETURN_INVALID_PARAMETER; } if ( (BaseAddress &~MtrrValidAddressMask) != 0 || (Length &~MtrrValidAddressMask) != 0 ) { return RETURN_UNSUPPORTED; } // // Check if Fixed MTRR // Status = RETURN_SUCCESS; while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) { Cr4 = PreMtrrChange (); Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length); PostMtrrChange (Cr4); if (RETURN_ERROR (Status)) { return Status; } } if (Length == 0) { // // A Length of 0 can only make sense for fixed MTTR ranges. // Since we just handled the fixed MTRRs, we can skip the // variable MTRR section. // goto Done; } // // Since memory ranges below 1MB will be overridden by the fixed MTRRs, // we can set the bade to 0 to save variable MTRRs. // if (BaseAddress == BASE_1MB) { BaseAddress = 0; Length += SIZE_1MB; } // // Check memory base address alignment // DivU64x64Remainder (BaseAddress, Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder); if (Remainder != 0) { DivU64x64Remainder (BaseAddress, Power2MaxMemory (Length), &Remainder); if (Remainder != 0) { Status = RETURN_UNSUPPORTED; goto Done; } } // // Check for overlap // UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr); OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr); if (OverLap) { Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr); if (RETURN_ERROR (Status)) { goto Done; } if (Length == 0) { // // Combined successfully // Status = RETURN_SUCCESS; goto Done; } } // // Program Variable MTRRs // // Avoid hardcode here and read data dynamically // if (UsedMtrr >= FirmwareVariableMtrrCount) { Status = RETURN_OUT_OF_RESOURCES; goto Done; } // // The memory type is the same with the type specified by // MTRR_LIB_IA32_MTRR_DEF_TYPE. // if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) { // // Invalidate the now-unused MTRRs // InvalidateMtrr(VariableMtrr); goto Done; } TempQword = Length; if (TempQword == Power2MaxMemory (TempQword)) { // // Invalidate the now-unused MTRRs // InvalidateMtrr(VariableMtrr); // // Find first unused MTRR // for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE; MsrNum < VariableMtrrEnd; MsrNum += 2 ) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } ProgramVariableMtrr ( MsrNum, BaseAddress, Length, MemoryType, MtrrValidAddressMask ); } else { Positive = GetDirection (TempQword, &MtrrNumber); if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) { Status = RETURN_OUT_OF_RESOURCES; goto Done; } // // Invalidate the now-unused MTRRs // InvalidateMtrr(VariableMtrr); // // Find first unused MTRR // for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE; MsrNum < VariableMtrrEnd; MsrNum += 2 ) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } if (!Positive) { Length = Power2MaxMemory (LShiftU64 (TempQword, 1)); ProgramVariableMtrr ( MsrNum, BaseAddress, Length, MemoryType, MtrrValidAddressMask ); BaseAddress += Length; TempQword = Length - TempQword; MemoryType = MTRR_CACHE_UNCACHEABLE; } do { // // Find unused MTRR // for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { break; } } Length = Power2MaxMemory (TempQword); if (!Positive) { BaseAddress -= Length; } ProgramVariableMtrr ( MsrNum, BaseAddress, Length, MemoryType, MtrrValidAddressMask ); if (Positive) { BaseAddress += Length; } TempQword -= Length; } while (TempQword > 0); } Done: return Status; }