+}\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