+/**\r
+ Sort FIT microcode entries based upon MicrocodeEntryPoint, from low to high.\r
+\r
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
+\r
+**/\r
+VOID\r
+SortFitMicrocodeInfo (\r
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
+ )\r
+{\r
+ FIT_MICROCODE_INFO *FitMicrocodeEntry;\r
+ FIT_MICROCODE_INFO *NextFitMicrocodeEntry;\r
+ FIT_MICROCODE_INFO TempFitMicrocodeEntry;\r
+ FIT_MICROCODE_INFO *FitMicrocodeEntryEnd;\r
+\r
+ FitMicrocodeEntry = MicrocodeFmpPrivate->FitMicrocodeInfo;\r
+ NextFitMicrocodeEntry = FitMicrocodeEntry + 1;\r
+ FitMicrocodeEntryEnd = MicrocodeFmpPrivate->FitMicrocodeInfo + MicrocodeFmpPrivate->FitMicrocodeEntryCount;\r
+ while (FitMicrocodeEntry < FitMicrocodeEntryEnd) {\r
+ while (NextFitMicrocodeEntry < FitMicrocodeEntryEnd) {\r
+ if (FitMicrocodeEntry->MicrocodeEntryPoint > NextFitMicrocodeEntry->MicrocodeEntryPoint) {\r
+ CopyMem (&TempFitMicrocodeEntry, FitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));\r
+ CopyMem (FitMicrocodeEntry, NextFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));\r
+ CopyMem (NextFitMicrocodeEntry, &TempFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));\r
+ }\r
+\r
+ NextFitMicrocodeEntry = NextFitMicrocodeEntry + 1;\r
+ }\r
+\r
+ FitMicrocodeEntry = FitMicrocodeEntry + 1;\r
+ NextFitMicrocodeEntry = FitMicrocodeEntry + 1;\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize FIT microcode information.\r
+\r
+ @param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
+\r
+ @return EFI_SUCCESS FIT microcode information is initialized.\r
+ @return EFI_OUT_OF_RESOURCES No enough resource for the initialization.\r
+ @return EFI_DEVICE_ERROR There is something wrong in FIT microcode entry.\r
+**/\r
+EFI_STATUS\r
+InitializeFitMicrocodeInfo (\r
+ IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
+ )\r
+{\r
+ UINT64 FitPointer;\r
+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;\r
+ UINT32 EntryNum;\r
+ UINT32 MicrocodeEntryNum;\r
+ UINT32 Index;\r
+ UINTN Address;\r
+ VOID *MicrocodePatchAddress;\r
+ UINTN MicrocodePatchRegionSize;\r
+ FIT_MICROCODE_INFO *FitMicrocodeInfo;\r
+ FIT_MICROCODE_INFO *FitMicrocodeInfoNext;\r
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
+ CPU_MICROCODE_HEADER *MicrocodeEntryPointNext;\r
+ UINTN FitMicrocodeIndex;\r
+ MICROCODE_INFO *MicrocodeInfo;\r
+ UINTN MicrocodeIndex;\r
+\r
+ if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
+ FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);\r
+ MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;\r
+ MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;\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
+ return EFI_SUCCESS;\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
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;\r
+\r
+ //\r
+ // Calculate microcode entry number.\r
+ //\r
+ MicrocodeEntryNum = 0;\r
+ for (Index = 0; Index < EntryNum; Index++) {\r
+ if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {\r
+ MicrocodeEntryNum++;\r
+ }\r
+ }\r
+ if (MicrocodeEntryNum == 0) {\r
+ //\r
+ // No FIT microcode entry.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Allocate buffer.\r
+ //\r
+ MicrocodeFmpPrivate->FitMicrocodeInfo = AllocateZeroPool (MicrocodeEntryNum * sizeof (FIT_MICROCODE_INFO));\r
+ if (MicrocodeFmpPrivate->FitMicrocodeInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ MicrocodeFmpPrivate->FitMicrocodeEntryCount = MicrocodeEntryNum;\r
+\r
+ MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+ MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
+\r
+ //\r
+ // Collect microcode entry info.\r
+ //\r
+ MicrocodeEntryNum = 0;\r
+ for (Index = 0; Index < EntryNum; Index++) {\r
+ if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {\r
+ Address = (UINTN) FitEntry[Index].Address;\r
+ if ((Address < (UINTN) MicrocodePatchAddress) ||\r
+ (Address >= ((UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize))) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "InitializeFitMicrocodeInfo - Address (0x%x) is not in Microcode Region\n",\r
+ Address\r
+ ));\r
+ goto ErrorExit;\r
+ }\r
+ FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[MicrocodeEntryNum];\r
+ FitMicrocodeInfo->MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) Address;\r
+ if ((*(UINT32 *) Address) == 0xFFFFFFFF) {\r
+ //\r
+ // It is the empty slot as long as the first dword is 0xFFFF_FFFF.\r
+ //\r
+ FitMicrocodeInfo->Empty = TRUE;\r
+ } else {\r
+ FitMicrocodeInfo->Empty = FALSE;\r
+ }\r
+ MicrocodeEntryNum++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Every microcode should have a FIT microcode entry.\r
+ //\r
+ for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {\r
+ MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex];\r
+ for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount; FitMicrocodeIndex++) {\r
+ FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];\r
+ if (MicrocodeInfo->MicrocodeEntryPoint == FitMicrocodeInfo->MicrocodeEntryPoint) {\r
+ FitMicrocodeInfo->TotalSize = MicrocodeInfo->TotalSize;\r
+ FitMicrocodeInfo->InUse = MicrocodeInfo->InUse;\r
+ break;\r
+ }\r
+ }\r
+ if (FitMicrocodeIndex >= MicrocodeFmpPrivate->FitMicrocodeEntryCount) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "InitializeFitMicrocodeInfo - There is no FIT microcode entry for Microcode (0x%x)\n",\r
+ MicrocodeInfo->MicrocodeEntryPoint\r
+ ));\r
+ goto ErrorExit;\r
+ }\r
+ }\r
+\r
+ SortFitMicrocodeInfo (MicrocodeFmpPrivate);\r
+\r
+ //\r
+ // Check overlap.\r
+ //\r
+ for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1; FitMicrocodeIndex++) {\r
+ FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];\r
+ MicrocodeEntryPoint = FitMicrocodeInfo->MicrocodeEntryPoint;\r
+ FitMicrocodeInfoNext = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex + 1];\r
+ MicrocodeEntryPointNext = FitMicrocodeInfoNext->MicrocodeEntryPoint;\r
+ if ((MicrocodeEntryPoint >= MicrocodeEntryPointNext) ||\r
+ ((FitMicrocodeInfo->TotalSize != 0) &&\r
+ ((UINTN) MicrocodeEntryPoint + FitMicrocodeInfo->TotalSize) >\r
+ (UINTN) MicrocodeEntryPointNext)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "InitializeFitMicrocodeInfo - There is overlap between FIT microcode entries (0x%x 0x%x)\n",\r
+ MicrocodeEntryPoint,\r
+ MicrocodeEntryPointNext\r
+ ));\r
+ goto ErrorExit;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);\r
+ MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;\r
+ MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r