MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));\r
}\r
}\r
+\r
+/**\r
+ Determine if a microcode patch will be loaded into memory.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+ @param[in] ProcessorSignature The processor signature field value\r
+ supported by a microcode patch.\r
+ @param[in] ProcessorFlags The prcessor flags field value supported by\r
+ a microcode patch.\r
+\r
+ @retval TRUE The specified microcode patch will be loaded.\r
+ @retval FALSE The specified microcode patch will not be loaded.\r
+**/\r
+BOOLEAN\r
+IsMicrocodePatchNeedLoad (\r
+ IN CPU_MP_DATA *CpuMpData,\r
+ IN UINT32 ProcessorSignature,\r
+ IN UINT32 ProcessorFlags\r
+ )\r
+{\r
+ UINTN Index;\r
+ CPU_AP_DATA *CpuData;\r
+\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ CpuData = &CpuMpData->CpuData[Index];\r
+ if ((ProcessorSignature == CpuData->ProcessorSignature) &&\r
+ (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Actual worker function that loads the required microcode patches into memory.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+ @param[in] Patches The pointer to an array of information on\r
+ the microcode patches that will be loaded\r
+ into memory.\r
+ @param[in] PatchCount The number of microcode patches that will\r
+ be loaded into memory.\r
+ @param[in] TotalLoadSize The total size of all the microcode patches\r
+ to be loaded.\r
+**/\r
+VOID\r
+LoadMicrocodePatchWorker (\r
+ IN OUT CPU_MP_DATA *CpuMpData,\r
+ IN MICROCODE_PATCH_INFO *Patches,\r
+ IN UINTN PatchCount,\r
+ IN UINTN TotalLoadSize\r
+ )\r
+{\r
+ UINTN Index;\r
+ VOID *MicrocodePatchInRam;\r
+ UINT8 *Walker;\r
+\r
+ ASSERT ((Patches != NULL) && (PatchCount != 0));\r
+\r
+ MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));\r
+ if (MicrocodePatchInRam == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Load all the required microcode patches into memory\r
+ //\r
+ for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {\r
+ CopyMem (\r
+ Walker,\r
+ (VOID *) Patches[Index].Address,\r
+ Patches[Index].Size\r
+ );\r
+\r
+ //\r
+ // Zero-fill the padding area\r
+ // Please note that AlignedSize will be no less than Size\r
+ //\r
+ ZeroMem (\r
+ Walker + Patches[Index].Size,\r
+ Patches[Index].AlignedSize - Patches[Index].Size\r
+ );\r
+\r
+ Walker += Patches[Index].AlignedSize;\r
+ }\r
+\r
+ //\r
+ // Update the microcode patch related fields in CpuMpData\r
+ //\r
+ CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;\r
+ CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
+ __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Load the required microcode patches data into memory.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+LoadMicrocodePatch (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
+ UINTN MicrocodeEnd;\r
+ UINTN DataSize;\r
+ UINTN TotalSize;\r
+ CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
+ UINT32 ExtendedTableCount;\r
+ CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
+ MICROCODE_PATCH_INFO *PatchInfoBuffer;\r
+ UINTN MaxPatchNumber;\r
+ UINTN PatchCount;\r
+ UINTN TotalLoadSize;\r
+ UINTN Index;\r
+ BOOLEAN NeedLoad;\r
+\r
+ //\r
+ // Initialize the microcode patch related fields in CpuMpData as the values\r
+ // specified by the PCD pair. If the microcode patches are loaded into memory,\r
+ // these fields will be updated.\r
+ //\r
+ CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
+ CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
+\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
+ MicrocodeEnd = (UINTN) MicrocodeEntryPoint +\r
+ (UINTN) CpuMpData->MicrocodePatchRegionSize;\r
+ if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {\r
+ //\r
+ // There is no microcode patches\r
+ //\r
+ return;\r
+ }\r
+\r
+ PatchCount = 0;\r
+ MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;\r
+ TotalLoadSize = 0;\r
+ PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));\r
+ if (PatchInfoBuffer == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Process the header of each microcode patch within the region.\r
+ // The purpose is to decide which microcode patch(es) will be loaded into memory.\r
+ //\r
+ do {\r
+ if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
+ //\r
+ // Padding data between the microcode patches, skip 1KB to check next entry.\r
+ //\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+ continue;\r
+ }\r
+\r
+ DataSize = MicrocodeEntryPoint->DataSize;\r
+ TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;\r
+ if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||\r
+ ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
+ (DataSize & 0x3) != 0 ||\r
+ (TotalSize & (SIZE_1KB - 1)) != 0 ||\r
+ TotalSize < DataSize\r
+ ) {\r
+ //\r
+ // Not a valid microcode header, skip 1KB to check next entry.\r
+ //\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode\r
+ // patch header with the CPUID and PlatformID of the processors within\r
+ // system to decide if it will be copied into memory\r
+ //\r
+ NeedLoad = IsMicrocodePatchNeedLoad (\r
+ CpuMpData,\r
+ MicrocodeEntryPoint->ProcessorSignature.Uint32,\r
+ MicrocodeEntryPoint->ProcessorFlags\r
+ );\r
+\r
+ //\r
+ // If the Extended Signature Table exists, check if the processor is in the\r
+ // support list\r
+ //\r
+ if ((!NeedLoad) && (DataSize != 0) &&\r
+ (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +\r
+ sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {\r
+ ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)\r
+ + DataSize + sizeof (CPU_MICROCODE_HEADER));\r
+ ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
+ ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
+\r
+ for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
+ //\r
+ // Avoid access content beyond MicrocodeEnd\r
+ //\r
+ if ((UINTN) ExtendedTable > MicrocodeEnd - sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended\r
+ // Signature Table entry with the CPUID and PlatformID of the processors\r
+ // within system to decide if it will be copied into memory\r
+ //\r
+ NeedLoad = IsMicrocodePatchNeedLoad (\r
+ CpuMpData,\r
+ ExtendedTable->ProcessorSignature.Uint32,\r
+ ExtendedTable->ProcessorFlag\r
+ );\r
+ if (NeedLoad) {\r
+ break;\r
+ }\r
+ ExtendedTable ++;\r
+ }\r
+ }\r
+\r
+ if (NeedLoad) {\r
+ PatchCount++;\r
+ if (PatchCount > MaxPatchNumber) {\r
+ //\r
+ // Current 'PatchInfoBuffer' cannot hold the information, double the size\r
+ // and allocate a new buffer.\r
+ //\r
+ if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {\r
+ //\r
+ // Overflow check for MaxPatchNumber\r
+ //\r
+ goto OnExit;\r
+ }\r
+\r
+ PatchInfoBuffer = ReallocatePool (\r
+ MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
+ 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
+ PatchInfoBuffer\r
+ );\r
+ if (PatchInfoBuffer == NULL) {\r
+ goto OnExit;\r
+ }\r
+ MaxPatchNumber = MaxPatchNumber * 2;\r
+ }\r
+\r
+ //\r
+ // Store the information of this microcode patch\r
+ //\r
+ if (TotalSize > ALIGN_VALUE (TotalSize, SIZE_1KB) ||\r
+ ALIGN_VALUE (TotalSize, SIZE_1KB) > MAX_UINTN - TotalLoadSize) {\r
+ goto OnExit;\r
+ }\r
+ PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;\r
+ PatchInfoBuffer[PatchCount - 1].Size = TotalSize;\r
+ PatchInfoBuffer[PatchCount - 1].AlignedSize = ALIGN_VALUE (TotalSize, SIZE_1KB);\r
+ TotalLoadSize += PatchInfoBuffer[PatchCount - 1].AlignedSize;\r
+ }\r
+\r
+ //\r
+ // Process the next microcode patch\r
+ //\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
+ } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
+\r
+ if (PatchCount != 0) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",\r
+ __FUNCTION__, PatchCount, TotalLoadSize\r
+ ));\r
+\r
+ LoadMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
+ }\r
+\r
+OnExit:\r
+ if (PatchInfoBuffer != NULL) {\r
+ FreePool (PatchInfoBuffer);\r
+ }\r
+ return;\r
+}\r
ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;\r
BistData = *(UINT32 *) ((UINTN) ApTopOfStack - sizeof (UINTN));\r
//\r
- // Do some AP initialize sync\r
- //\r
- ApInitializeSync (CpuMpData);\r
- //\r
// CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,\r
// to initialize AP in InitConfig path.\r
// NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.\r
UINTN ApResetVectorSize;\r
UINTN BackupBufferAddr;\r
UINTN ApIdtBase;\r
- VOID *MicrocodePatchInRam;\r
\r
OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
if (OldCpuMpData == NULL) {\r
CpuMpData->SwitchBspFlag = FALSE;\r
CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
- if (OldCpuMpData == NULL) {\r
- CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
- //\r
- // If platform has more than one CPU, relocate microcode to memory to reduce\r
- // loading microcode time.\r
- //\r
- MicrocodePatchInRam = NULL;\r
- if (MaxLogicalProcessorNumber > 1) {\r
- MicrocodePatchInRam = AllocatePages (\r
- EFI_SIZE_TO_PAGES (\r
- (UINTN)CpuMpData->MicrocodePatchRegionSize\r
- )\r
- );\r
- }\r
- if (MicrocodePatchInRam == NULL) {\r
- //\r
- // there is only one processor, or no microcode patch is available, or\r
- // memory allocation failed\r
- //\r
- CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
- } else {\r
- //\r
- // there are multiple processors, and a microcode patch is available, and\r
- // memory allocation succeeded\r
- //\r
- CopyMem (\r
- MicrocodePatchInRam,\r
- (VOID *)(UINTN)PcdGet64 (PcdCpuMicrocodePatchAddress),\r
- (UINTN)CpuMpData->MicrocodePatchRegionSize\r
- );\r
- CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;\r
- }\r
- }else {\r
+ if (OldCpuMpData != NULL) {\r
CpuMpData->MicrocodePatchRegionSize = OldCpuMpData->MicrocodePatchRegionSize;\r
CpuMpData->MicrocodePatchAddress = OldCpuMpData->MicrocodePatchAddress;\r
}\r
(UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
}\r
//\r
- // Load Microcode on BSP\r
- //\r
- MicrocodeDetect (CpuMpData, TRUE);\r
- //\r
- // Store BSP's MTRR setting\r
- //\r
- MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
- //\r
// Enable the local APIC for Virtual Wire Mode.\r
//\r
ProgramVirtualWireMode ();\r
//\r
CollectProcessorCount (CpuMpData);\r
}\r
+\r
+ //\r
+ // Load required microcode patches data into memory\r
+ //\r
+ LoadMicrocodePatch (CpuMpData);\r
} else {\r
//\r
// APs have been wakeup before, just get the CPU Information\r
//\r
CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
- CpuMpData->InitFlag = ApInitReconfig;\r
CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;\r
CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
CpuMpData->CpuData[Index].ApFunction = 0;\r
CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (CPU_VOLATILE_REGISTERS));\r
}\r
- if (MaxLogicalProcessorNumber > 1) {\r
- //\r
- // Wakeup APs to do some AP initialize sync\r
- //\r
- WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);\r
- //\r
- // Wait for all APs finished initialization\r
- //\r
- while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
- CpuPause ();\r
- }\r
- CpuMpData->InitFlag = ApInitDone;\r
- for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
- SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
- }\r
+ }\r
+\r
+ //\r
+ // Detect and apply Microcode on BSP\r
+ //\r
+ MicrocodeDetect (CpuMpData, TRUE);\r
+ //\r
+ // Store BSP's MTRR setting\r
+ //\r
+ MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
+\r
+ //\r
+ // Wakeup APs to do some AP initialize sync (Microcode & MTRR)\r
+ //\r
+ if (CpuMpData->CpuCount > 1) {\r
+ WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);\r
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
+ CpuPause ();\r
+ }\r
+\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
}\r
}\r
\r