]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
IntelSiliconPkg MicrocodeUpdateDxe: Honor FIT table
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeFmp.c
index ebde93a91eb3034b2647e6e5a2d479649f701e9d..bc1387b3dddda94d702587cb7d2ee67566dd5ed1 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Produce FMP instance for Microcode.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -161,7 +161,7 @@ FmpGetImageInfo (
   @retval EFI_INVALID_PARAMETER  The Image was NULL.\r
   @retval EFI_NOT_FOUND          The current image is not copied to the buffer.\r
   @retval EFI_UNSUPPORTED        The operation is not supported.\r
-  @retval EFI_SECURITY_VIOLATIO  The operation could not be performed due to an authentication failure.\r
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -241,7 +241,7 @@ FmpGetImage (
   @retval EFI_ABORTED            The operation is aborted.\r
   @retval EFI_INVALID_PARAMETER  The Image was NULL.\r
   @retval EFI_UNSUPPORTED        The operation is not supported.\r
-  @retval EFI_SECURITY_VIOLATIO  The operation could not be performed due to an authentication failure.\r
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -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
@@ -307,7 +307,7 @@ FmpSetImage (
   @retval EFI_SUCCESS            The image was successfully checked.\r
   @retval EFI_INVALID_PARAMETER  The Image was NULL.\r
   @retval EFI_UNSUPPORTED        The operation is not supported.\r
-  @retval EFI_SECURITY_VIOLATIO  The operation could not be performed due to an authentication failure.\r
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -397,7 +397,7 @@ FmpGetPackageInfo (
   @retval EFI_INVALID_PARAMETER  The PackageVersionName length is longer than the value\r
                                  returned in PackageVersionNameMaxLen.\r
   @retval EFI_UNSUPPORTED        The operation is not supported.\r
-  @retval EFI_SECURITY_VIOLATIO  The operation could not be performed due to an authentication failure.\r
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
 \r
 **/\r
 EFI_STATUS\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