Enhance the MTRR lib to support the case where alignment of base address < length.

Signed-off by: rsun3
Reviewed-by:   hhuan13

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12330 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
rsun3 2011-09-13 03:06:48 +00:00
parent 0f87f732e9
commit 1a2ad6fca7
1 changed files with 126 additions and 91 deletions

View File

@ -586,12 +586,17 @@ Power2MaxMemory (
/** /**
Check the direction to program variable MTRRs. Determine the MTRR numbers used to program a memory range.
This function determines which direction of programming the variable This function first checks the alignment of the base address. If the alignment of the base address <= Length,
MTRRs will use fewer MTRRs. cover the memory range (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and Length -= alignment.
Repeat the step until alignment > Length.
@param Input Length of Memory to program MTRR Then this function determines which direction of programming the variable MTRRs for the remaining length
will use fewer MTRRs.
@param BaseAddress Length of Memory to program MTRR
@param Length Length of Memory to program MTRR
@param MtrrNumber Pointer to the number of necessary MTRRs @param MtrrNumber Pointer to the number of necessary MTRRs
@retval TRUE Positive direction is better. @retval TRUE Positive direction is better.
@ -599,16 +604,41 @@ Power2MaxMemory (
**/ **/
BOOLEAN BOOLEAN
GetDirection ( GetMtrrNumberAndDirection (
IN UINT64 Input, IN UINT64 BaseAddress,
IN UINT64 Length,
IN UINTN *MtrrNumber IN UINTN *MtrrNumber
) )
{ {
UINT64 TempQword; UINT64 TempQword;
UINT64 Alignment;
UINT32 Positive; UINT32 Positive;
UINT32 Subtractive; UINT32 Subtractive;
TempQword = Input; *MtrrNumber = 0;
if (BaseAddress != 0) {
do {
//
// Calculate the alignment of the base address.
//
Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
if (Alignment > Length) {
break;
}
(*MtrrNumber)++;
BaseAddress += Alignment;
Length -= Alignment;
} while (TRUE);
if (Length == 0) {
return TRUE;
}
}
TempQword = Length;
Positive = 0; Positive = 0;
Subtractive = 0; Subtractive = 0;
@ -617,7 +647,7 @@ GetDirection (
Positive++; Positive++;
} while (TempQword != 0); } while (TempQword != 0);
TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input; TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
Subtractive++; Subtractive++;
do { do {
TempQword -= Power2MaxMemory (TempQword); TempQword -= Power2MaxMemory (TempQword);
@ -625,10 +655,10 @@ GetDirection (
} while (TempQword != 0); } while (TempQword != 0);
if (Positive <= Subtractive) { if (Positive <= Subtractive) {
*MtrrNumber = Positive; *MtrrNumber += Positive;
return TRUE; return TRUE;
} else { } else {
*MtrrNumber = Subtractive; *MtrrNumber += Subtractive;
return FALSE; return FALSE;
} }
} }
@ -887,7 +917,7 @@ MtrrSetMemoryAttribute (
UINT64 TempQword; UINT64 TempQword;
RETURN_STATUS Status; RETURN_STATUS Status;
UINT64 MemoryType; UINT64 MemoryType;
UINT64 Remainder; UINT64 Alignment;
BOOLEAN OverLap; BOOLEAN OverLap;
BOOLEAN Positive; BOOLEAN Positive;
UINT32 MsrNum; UINT32 MsrNum;
@ -964,18 +994,6 @@ MtrrSetMemoryAttribute (
Length += SIZE_1MB; 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 // Check for overlap
// //
@ -1018,22 +1036,75 @@ MtrrSetMemoryAttribute (
goto Done; 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; TempQword = Length;
if (!Positive) {
if (TempQword == Power2MaxMemory (TempQword)) { Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
//
// Invalidate the now-unused MTRRs
//
InvalidateMtrr(VariableMtrr);
// //
// Find first unused MTRR // Find unused MTRR
// //
for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE; for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
MsrNum < VariableMtrrEnd;
MsrNum += 2
) {
if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
break; break;
} }
@ -1046,76 +1117,40 @@ MtrrSetMemoryAttribute (
MemoryType, MemoryType,
MtrrValidAddressMask MtrrValidAddressMask
); );
} else { BaseAddress += Length;
TempQword = Length - TempQword;
Positive = GetDirection (TempQword, &MtrrNumber); MemoryType = MTRR_CACHE_UNCACHEABLE;
}
if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
Status = RETURN_OUT_OF_RESOURCES;
goto Done;
}
do {
// //
// Invalidate the now-unused MTRRs // Find unused MTRR
// //
InvalidateMtrr(VariableMtrr); for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
//
// 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) { if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
break; break;
} }
} }
Length = Power2MaxMemory (TempQword);
if (!Positive) { if (!Positive) {
Length = Power2MaxMemory (LShiftU64 (TempQword, 1)); BaseAddress -= Length;
ProgramVariableMtrr (
MsrNum,
BaseAddress,
Length,
MemoryType,
MtrrValidAddressMask
);
BaseAddress += Length;
TempQword = Length - TempQword;
MemoryType = MTRR_CACHE_UNCACHEABLE;
} }
do { ProgramVariableMtrr (
// MsrNum,
// Find unused MTRR BaseAddress,
// Length,
for (; MsrNum < VariableMtrrEnd; MsrNum += 2) { MemoryType,
if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) { MtrrValidAddressMask
break; );
}
}
Length = Power2MaxMemory (TempQword); if (Positive) {
if (!Positive) { BaseAddress += Length;
BaseAddress -= Length; }
} TempQword -= Length;
ProgramVariableMtrr ( } while (TempQword > 0);
MsrNum,
BaseAddress,
Length,
MemoryType,
MtrrValidAddressMask
);
if (Positive) {
BaseAddress += Length;
}
TempQword -= Length;
} while (TempQword > 0);
}
Done: Done:
DEBUG((DEBUG_CACHE, " Status = %r\n", Status)); DEBUG((DEBUG_CACHE, " Status = %r\n", Status));