+\r
+/**\r
+ Shadow the required microcode patches data into memory according to FIT microcode entry.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+\r
+ @return EFI_SUCCESS Microcode patch is shadowed into memory.\r
+ @return EFI_UNSUPPORTED FIT based microcode shadowing is not supported.\r
+ @return EFI_OUT_OF_RESOURCES No enough memory resource.\r
+ @return EFI_NOT_FOUND There is something wrong in FIT microcode entry.\r
+\r
+**/\r
+EFI_STATUS\r
+ShadowMicrocodePatchByFit (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ UINT64 FitPointer;\r
+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;\r
+ UINT32 EntryNum;\r
+ UINT32 Index;\r
+ MICROCODE_PATCH_INFO *PatchInfoBuffer;\r
+ UINTN MaxPatchNumber;\r
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
+ UINTN PatchCount;\r
+ UINTN TotalSize;\r
+ UINTN TotalLoadSize;\r
+\r
+ if (!FeaturePcdGet (PcdCpuShadowMicrocodeByFit)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FitPointer = *(UINT64 *) (UINTN) FIT_POINTER_ADDRESS;\r
+ if ((FitPointer == 0) ||\r
+ (FitPointer == 0xFFFFFFFFFFFFFFFF) ||\r
+ (FitPointer == 0xEEEEEEEEEEEEEEEE)) {\r
+ //\r
+ // No FIT table.\r
+ //\r
+ ASSERT (FALSE);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *) (UINTN) FitPointer;\r
+ if ((FitEntry[0].Type != FIT_TYPE_00_HEADER) ||\r
+ (FitEntry[0].Address != FIT_TYPE_00_SIGNATURE)) {\r
+ //\r
+ // Invalid FIT table, treat it as no FIT table.\r
+ //\r
+ ASSERT (FALSE);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;\r
+\r
+ //\r
+ // Calculate microcode entry number\r
+ //\r
+ MaxPatchNumber = 0;\r
+ for (Index = 0; Index < EntryNum; Index++) {\r
+ if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {\r
+ MaxPatchNumber++;\r
+ }\r
+ }\r
+ if (MaxPatchNumber == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));\r
+ if (PatchInfoBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Fill up microcode patch info buffer according to FIT table.\r
+ //\r
+ PatchCount = 0;\r
+ TotalLoadSize = 0;\r
+ for (Index = 0; Index < EntryNum; Index++) {\r
+ if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) FitEntry[Index].Address;\r
+ TotalSize = (MicrocodeEntryPoint->DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;\r
+ if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) {\r
+ PatchInfoBuffer[PatchCount].Address = (UINTN) MicrocodeEntryPoint;\r
+ PatchInfoBuffer[PatchCount].Size = TotalSize;\r
+ TotalLoadSize += TotalSize;\r
+ PatchCount++;\r
+ }\r
+ }\r
+ }\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
+ ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
+ }\r
+\r
+ FreePool (PatchInfoBuffer);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Shadow the required microcode patches data into memory.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+ShadowMicrocodeUpdatePatch (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = ShadowMicrocodePatchByFit (CpuMpData);\r
+ if (EFI_ERROR (Status)) {\r
+ ShadowMicrocodePatchByPcd (CpuMpData);\r
+ }\r
+}\r