UefiCpuPkg/MtrrLib: Fixed bug if length is less than Fixed-MTRR range

Currently, if the memory length to be programmed is less than the remaining size
of one Fixed-MTRR supported, RETURN_UNSUPPORTED returned. This is not correct.
This is one regression at 07e8892090 when we
updated ProgramFixedMtrr() to remove the loop of calculating Fixed-MTRR Mask.

This fix will calculate Right offset in Fixed-MTRR beside left offset. It
supports small length (less than remaining size supported by Fixed-MTRR) to be
programmed.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
This commit is contained in:
Jeff Fan 2016-06-06 10:04:11 +08:00
parent 626f6f6e74
commit eecad34987
1 changed files with 48 additions and 23 deletions

View File

@ -20,8 +20,8 @@
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
#define OR_SEED 0x01010101 #define OR_SEED 0x0101010101010101ull
#define CLEAR_SEED 0xFFFFFFFF #define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
// //
// Context to save and restore when MTRRs are programmed // Context to save and restore when MTRRs are programmed
@ -462,14 +462,15 @@ ProgramFixedMtrr (
) )
{ {
UINT32 MsrNum; UINT32 MsrNum;
UINT32 ByteShift; UINT32 LeftByteShift;
UINT32 OrMask[2]; UINT32 RightByteShift;
UINT32 ClearMask[2]; UINT64 OrMask;
UINT64 ClearMask;
UINT64 SubLength; UINT64 SubLength;
*(UINT64 *)OrMask = 0; //
*(UINT64 *)ClearMask = 0; // Find the fixed MTRR index to be programmed
//
for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) { for (MsrNum = *LastMsrNum + 1; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) && if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
(*Base < (*Base <
@ -488,36 +489,60 @@ ProgramFixedMtrr (
} }
// //
// We found the fixed MTRR to be programmed // Find the begin offset in fixed MTRR and calculate byte offset of left shift
// //
ByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrNum].BaseAddress)
/ mMtrrLibFixedMtrrTable[MsrNum].Length; / mMtrrLibFixedMtrrTable[MsrNum].Length;
if (ByteShift >= 8) { if (LeftByteShift >= 8) {
return RETURN_UNSUPPORTED; return RETURN_UNSUPPORTED;
} }
if (ByteShift < 4) { //
OrMask[0] = OR_SEED * (UINT32)MemoryCacheType; // Find the end offset in fixed MTRR and calculate byte offset of right shift
ClearMask[0] = CLEAR_SEED; //
OrMask[1] = (OR_SEED * (UINT32)MemoryCacheType) >> ((4 - ByteShift) * 8); SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - LeftByteShift);
ClearMask[1] = CLEAR_SEED >> ((4 - ByteShift) * 8); if (*Length >= SubLength) {
RightByteShift = 0;
} else { } else {
OrMask[0] = (OR_SEED * (UINT32)MemoryCacheType) >> ((8 - ByteShift) * 8); RightByteShift = 8 - LeftByteShift -
ClearMask[0] = CLEAR_SEED >> ((8 - ByteShift) * 8); (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrNum].Length;
if ((LeftByteShift >= 8) ||
(((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrNum].Length) != 0)
) {
return RETURN_UNSUPPORTED;
}
//
// Update SubLength by actual length
//
SubLength = *Length;
} }
SubLength = mMtrrLibFixedMtrrTable[MsrNum].Length * (8 - ByteShift); ClearMask = CLEAR_SEED;
if (*Length < SubLength) { OrMask = MultU64x32 (OR_SEED, (UINT32)MemoryCacheType);
return RETURN_UNSUPPORTED;
if (LeftByteShift != 0) {
//
// Clear the low bits by LeftByteShift
//
ClearMask &= LShiftU64 (ClearMask, LeftByteShift * 8);
OrMask &= LShiftU64 (OrMask, LeftByteShift * 8);
}
if (RightByteShift != 0) {
//
// Clear the high bits by RightByteShift
//
ClearMask &= RShiftU64 (ClearMask, RightByteShift * 8);
OrMask &= RShiftU64 (OrMask, RightByteShift * 8);
} }
*Length -= SubLength; *Length -= SubLength;
*Base += SubLength; *Base += SubLength;
*LastMsrNum = MsrNum; *LastMsrNum = MsrNum;
*ReturnClearMask = *(UINT64 *)ClearMask; *ReturnClearMask = ClearMask;
*ReturnOrMask = *(UINT64 *)OrMask; *ReturnOrMask = OrMask;
return RETURN_SUCCESS; return RETURN_SUCCESS;
} }