/**\r
Detect whether specified processor can find matching microcode patch and load it.\r
\r
- @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+ Microcode Payload as the following format:\r
+ +----------------------------------------+------------------+\r
+ | CPU_MICROCODE_HEADER | |\r
+ +----------------------------------------+ CheckSum Part1 |\r
+ | Microcode Binary | |\r
+ +----------------------------------------+------------------+\r
+ | CPU_MICROCODE_EXTENDED_TABLE_HEADER | |\r
+ +----------------------------------------+ CheckSum Part2 |\r
+ | CPU_MICROCODE_EXTENDED_TABLE | |\r
+ | ... | |\r
+ +----------------------------------------+------------------+\r
+\r
+ There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.\r
+ The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount\r
+ of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.\r
+\r
+ When we are trying to verify the CheckSum32 with extended table.\r
+ We should use the fields of exnteded table to replace the corresponding\r
+ fields in CPU_MICROCODE_HEADER structure, and recalculate the\r
+ CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named\r
+ it as CheckSum Part3.\r
+\r
+ The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER\r
+ and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2\r
+ is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.\r
+\r
+ Only ProcessorSignature, ProcessorFlag and CheckSum are different between\r
+ CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.\r
+ Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
+ When we are going to calculate CheckSum32, just should use the corresponding part\r
+ of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.\r
+\r
+ Notes: CheckSum32 is not a strong verification.\r
+ It does not guarantee that the data has not been modified.\r
+ CPU has its own mechanism to verify Microcode Binary part.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+ @param[in] IsBspCallIn Indicate whether the caller is BSP or not.\r
**/\r
VOID\r
MicrocodeDetect (\r
- IN CPU_MP_DATA *CpuMpData\r
+ IN CPU_MP_DATA *CpuMpData,\r
+ IN BOOLEAN IsBspCallIn\r
)\r
{\r
UINT32 ExtendedTableLength;\r
UINT32 LatestRevision;\r
UINTN TotalSize;\r
UINT32 CheckSum32;\r
+ UINT32 InCompleteCheckSum32;\r
BOOLEAN CorrectMicrocode;\r
VOID *MicrocodeData;\r
MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;\r
+ UINT32 ProcessorFlags;\r
+ UINT32 ThreadId;\r
+\r
+ //\r
+ // set ProcessorFlags to suppress incorrect compiler/analyzer warnings\r
+ //\r
+ ProcessorFlags = 0;\r
\r
if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
//\r
}\r
\r
CurrentRevision = GetCurrentMicrocodeSignature ();\r
- if (CurrentRevision != 0) {\r
+ if (CurrentRevision != 0 && !IsBspCallIn) {\r
//\r
// Skip loading microcode if it has been loaded successfully\r
//\r
return;\r
}\r
\r
+ GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);\r
+ if (ThreadId != 0) {\r
+ //\r
+ // Skip loading microcode if it is not the first thread in one core.\r
+ //\r
+ return;\r
+ }\r
+\r
ExtendedTableLength = 0;\r
//\r
// Here data of CPUID leafs have not been collected into context buffer, so\r
PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
\r
+ //\r
+ // Check whether AP has same processor with BSP.\r
+ // If yes, direct use microcode info saved by BSP.\r
+ //\r
+ if (!IsBspCallIn) {\r
+ if ((CpuMpData->ProcessorSignature == Eax.Uint32) &&\r
+ (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) {\r
+ MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress;\r
+ LatestRevision = CpuMpData->MicrocodeRevision;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
LatestRevision = 0;\r
MicrocodeData = NULL;\r
MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);\r
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
+\r
do {\r
//\r
// Check if the microcode is for the Cpu and the version is newer\r
// and the update can be processed on the platform\r
//\r
CorrectMicrocode = FALSE;\r
+\r
+ if (MicrocodeEntryPoint->DataSize == 0) {\r
+ TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;\r
+ } else {\r
+ TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;\r
+ }\r
+\r
+ ///\r
+ /// Check overflow and whether TotalSize is aligned with 4 bytes.\r
+ ///\r
+ if ( ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
+ (TotalSize & 0x3) != 0\r
+ ) {\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
+ //\r
+ InCompleteCheckSum32 = CalculateSum32 (\r
+ (UINT32 *) MicrocodeEntryPoint,\r
+ TotalSize\r
+ );\r
+ InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+ InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
+ InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
+\r
if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
//\r
// It is the microcode header. It is not the padding data between microcode patches\r
MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
(MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
) {\r
- if (MicrocodeEntryPoint->DataSize == 0) {\r
- CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);\r
- } else {\r
- CheckSum32 = CalculateSum32 (\r
- (UINT32 *) MicrocodeEntryPoint,\r
- MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)\r
- );\r
- }\r
+ //\r
+ // Calculate CheckSum Part1.\r
+ //\r
+ CheckSum32 = InCompleteCheckSum32;\r
+ CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+ CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;\r
+ CheckSum32 += MicrocodeEntryPoint->Checksum;\r
if (CheckSum32 == 0) {\r
CorrectMicrocode = TRUE;\r
+ ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;\r
}\r
} else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
(MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
// Calculate Extended Checksum\r
//\r
if ((ExtendedTableLength % 4) == 0) {\r
+ //\r
+ // Calculate CheckSum Part2.\r
+ //\r
CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);\r
if (CheckSum32 == 0) {\r
//\r
ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
- CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
+ //\r
+ // Calculate CheckSum Part3.\r
+ //\r
+ CheckSum32 = InCompleteCheckSum32;\r
+ CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
+ CheckSum32 += ExtendedTable->ProcessorFlag;\r
+ CheckSum32 += ExtendedTable->Checksum;\r
if (CheckSum32 == 0) {\r
//\r
// Verify Header\r
// Find one\r
//\r
CorrectMicrocode = TRUE;\r
+ ProcessorFlags = ExtendedTable->ProcessorFlag;\r
break;\r
}\r
}\r
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
} while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
\r
+Done:\r
if (LatestRevision > CurrentRevision) {\r
//\r
// BIOS only authenticate updates that contain a numerically larger revision\r
ReleaseSpinLock(&CpuMpData->MpLock);\r
}\r
}\r
+\r
+ if (IsBspCallIn && (LatestRevision != 0)) {\r
+ //\r
+ // Save BSP processor info and microcode info for later AP use.\r
+ //\r
+ CpuMpData->ProcessorSignature = Eax.Uint32;\r
+ CpuMpData->ProcessorFlags = ProcessorFlags;\r
+ CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData;\r
+ CpuMpData->MicrocodeRevision = LatestRevision;\r
+ DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \\r
+ MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));\r
+ }\r
}\r