IntelSiliconPkg MicrocodeUpdateDxe: Honor FIT table
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeFmp.c
index ef5e630..bc1387b 100644 (file)
@@ -272,7 +272,7 @@ FmpSetImage (
   }\r
 \r
   Status = MicrocodeWrite(MicrocodeFmpPrivate, (VOID *)Image, ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason);\r
-  DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
+  DEBUG((DEBUG_INFO, "SetImage - LastAttempt Version - 0x%x, Status - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
   VarStatus = gRT->SetVariable(\r
                      MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,\r
                      &gEfiCallerIdGuid,\r
@@ -280,7 +280,7 @@ FmpSetImage (
                      sizeof(MicrocodeFmpPrivate->LastAttempt),\r
                      &MicrocodeFmpPrivate->LastAttempt\r
                      );\r
-  DEBUG((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus));\r
+  DEBUG((DEBUG_INFO, "SetLastAttempt - %r\n", VarStatus));\r
 \r
   if (!EFI_ERROR(Status)) {\r
     InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);\r
@@ -414,6 +414,212 @@ FmpSetPackageInfo (
   return EFI_UNSUPPORTED;\r
 }\r
 \r
+/**\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
 /**\r
   Initialize Processor Microcode Index.\r
 \r
@@ -460,14 +666,16 @@ InitializedProcessorMicrocodeIndex (
 \r
   @param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
 \r
-  @return EFI_SUCCESS Microcode Descriptor is initialized.\r
+  @return EFI_SUCCESS           Microcode Descriptor is initialized.\r
+  @return EFI_OUT_OF_RESOURCES  No enough resource for the initialization.\r
 **/\r
 EFI_STATUS\r
 InitializeMicrocodeDescriptor (\r
   IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
   )\r
 {\r
-  UINT8    CurrentMicrocodeCount;\r
+  EFI_STATUS Status;\r
+  UINT8      CurrentMicrocodeCount;\r
 \r
   CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, 0, NULL, NULL);\r
 \r
@@ -496,6 +704,7 @@ InitializeMicrocodeDescriptor (
   if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {\r
     MicrocodeFmpPrivate->MicrocodeInfo = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));\r
     if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {\r
+      FreePool (MicrocodeFmpPrivate->ImageDescriptor);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
   }\r
@@ -505,6 +714,14 @@ InitializeMicrocodeDescriptor (
 \r
   InitializedProcessorMicrocodeIndex (MicrocodeFmpPrivate);\r
 \r
+  Status = InitializeFitMicrocodeInfo (MicrocodeFmpPrivate);\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool (MicrocodeFmpPrivate->ImageDescriptor);\r
+    FreePool (MicrocodeFmpPrivate->MicrocodeInfo);\r
+    DEBUG((DEBUG_ERROR, "InitializeFitMicrocodeInfo - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -513,7 +730,8 @@ InitializeMicrocodeDescriptor (
 \r
   @param[in] MicrocodeFmpPrivate private data structure to be initialized.\r
 \r
-  @return EFI_SUCCESS private data is initialized.\r
+  @return EFI_SUCCESS           Processor information is initialized.\r
+  @return EFI_OUT_OF_RESOURCES  No enough resource for the initialization.\r
 **/\r
 EFI_STATUS\r
 InitializeProcessorInfo (\r
@@ -583,6 +801,7 @@ DumpPrivateInfo (
   PROCESSOR_INFO                       *ProcessorInfo;\r
   MICROCODE_INFO                       *MicrocodeInfo;\r
   EFI_FIRMWARE_IMAGE_DESCRIPTOR        *ImageDescriptor;\r
+  FIT_MICROCODE_INFO                   *FitMicrocodeInfo;\r
 \r
   DEBUG ((DEBUG_INFO, "ProcessorInfo:\n"));\r
   DEBUG ((DEBUG_INFO, "  ProcessorCount - 0x%x\n", MicrocodeFmpPrivate->ProcessorCount));\r
@@ -635,6 +854,23 @@ DumpPrivateInfo (
     DEBUG((DEBUG_VERBOSE, "    LastAttemptStatus           - 0x%x\n", ImageDescriptor[Index].LastAttemptStatus));\r
     DEBUG((DEBUG_VERBOSE, "    HardwareInstance            - 0x%lx\n", ImageDescriptor[Index].HardwareInstance));\r
   }\r
+\r
+  if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
+    DEBUG ((DEBUG_INFO, "FitMicrocodeInfo:\n"));\r
+    FitMicrocodeInfo = MicrocodeFmpPrivate->FitMicrocodeInfo;\r
+    DEBUG ((DEBUG_INFO, "  FitMicrocodeEntryCount - 0x%x\n", MicrocodeFmpPrivate->FitMicrocodeEntryCount));\r
+    for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
+      DEBUG ((\r
+        DEBUG_INFO,\r
+        "  FitMicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x, 0x%x)\n",\r
+        Index,\r
+        FitMicrocodeInfo[Index].MicrocodeEntryPoint,\r
+        FitMicrocodeInfo[Index].TotalSize,\r
+        FitMicrocodeInfo[Index].InUse,\r
+        FitMicrocodeInfo[Index].Empty\r
+        ));\r
+    }\r
+  }\r
 }\r
 \r
 /**\r
@@ -671,8 +907,8 @@ InitializePrivateData (
                      &VarSize,\r
                      &MicrocodeFmpPrivate->LastAttempt\r
                      );\r
-  DEBUG((DEBUG_INFO, "GetLastAttemp - %r\n", VarStatus));\r
-  DEBUG((DEBUG_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
+  DEBUG((DEBUG_INFO, "GetLastAttempt - %r\n", VarStatus));\r
+  DEBUG((DEBUG_INFO, "GetLastAttempt Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));\r
 \r
   Result = GetMicrocodeRegion(&MicrocodeFmpPrivate->MicrocodePatchAddress, &MicrocodeFmpPrivate->MicrocodePatchRegionSize);\r
   if (!Result) {\r
@@ -688,6 +924,7 @@ InitializePrivateData (
 \r
   Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);\r
   if (EFI_ERROR(Status)) {\r
+    FreePool (MicrocodeFmpPrivate->ProcessorInfo);\r
     DEBUG((DEBUG_ERROR, "InitializeMicrocodeDescriptor - %r\n", Status));\r
     return Status;\r
   }\r