]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
IntelSiliconPkg/MicrocodeUpdate: Fix incorrect checksum issue
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeUpdate.c
index 4e8f1d5fd8a881d71928d75c78c5b547738f0b99..e45c7a8def0d104dda1d21ffa1112e00fe312e61 100644 (file)
@@ -8,7 +8,7 @@
 \r
   MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.\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
@@ -368,7 +368,7 @@ GetMatchedProcessor (
                                          On output, the index of target CPU which matches the Microcode.\r
 \r
   @retval EFI_SUCCESS               The Microcode image passes verification.\r
-  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.\r
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupted.\r
   @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.\r
   @retval EFI_UNSUPPORTED           The Microcode ProcessorSignature or ProcessorFlags is incorrect.\r
   @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.\r
@@ -390,6 +390,7 @@ VerifyMicrocode (
   UINTN                                   DataSize;\r
   UINT32                                  CurrentRevision;\r
   PROCESSOR_INFO                          *ProcessorInfo;\r
+  UINT32                                  InCompleteCheckSum32;\r
   UINT32                                  CheckSum32;\r
   UINTN                                   ExtendedTableLength;\r
   UINT32                                  ExtendedTableCount;\r
@@ -421,7 +422,7 @@ VerifyMicrocode (
     return EFI_INCOMPATIBLE_VERSION;\r
   }\r
   //\r
-  // Check Size\r
+  // Check TotalSize\r
   //\r
   if (MicrocodeEntryPoint->DataSize == 0) {\r
     TotalSize = 2048;\r
@@ -436,8 +437,16 @@ VerifyMicrocode (
     }\r
     return EFI_VOLUME_CORRUPTED;\r
   }\r
+  if ((TotalSize & (SIZE_1KB - 1)) != 0) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize is not multiples of 1024 bytes (1 KBytes)\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
+    }\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
   if (TotalSize != ImageSize) {\r
-    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\n"));\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize not equal to ImageSize\n"));\r
     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
     if (AbortReason != NULL) {\r
       *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
@@ -445,7 +454,7 @@ VerifyMicrocode (
     return EFI_VOLUME_CORRUPTED;\r
   }\r
   //\r
-  // Check CheckSum32\r
+  // Check DataSize\r
   //\r
   if (MicrocodeEntryPoint->DataSize == 0) {\r
     DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);\r
@@ -461,13 +470,16 @@ VerifyMicrocode (
     return EFI_VOLUME_CORRUPTED;\r
   }\r
   if ((DataSize & 0x3) != 0) {\r
-    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize not aligned\n"));\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));\r
     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
     if (AbortReason != NULL) {\r
       *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
     }\r
     return EFI_VOLUME_CORRUPTED;\r
   }\r
+  //\r
+  // Check CheckSum32\r
+  //\r
   CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));\r
   if (CheckSum32 != 0) {\r
     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));\r
@@ -477,6 +489,10 @@ VerifyMicrocode (
     }\r
     return EFI_VOLUME_CORRUPTED;\r
   }\r
+  InCompleteCheckSum32 = CheckSum32;\r
+  InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+  InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
+  InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
 \r
   //\r
   // Check ProcessorSignature/ProcessorFlags\r
@@ -494,18 +510,30 @@ VerifyMicrocode (
       //\r
       // Calculate Extended Checksum\r
       //\r
-      if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) != 0)) {\r
+      if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) == 0)) {\r
         CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
-        if (CheckSum32 == 0) {\r
+        if (CheckSum32 != 0) {\r
+          //\r
+          // Checksum incorrect\r
+          //\r
+          DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for extended table is incorrect\n"));\r
+        } else {\r
           //\r
           // Checksum correct\r
           //\r
           ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
-          if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
+          if (ExtendedTableCount > (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
+            DEBUG((DEBUG_ERROR, "VerifyMicrocode - ExtendedTableCount %d is too big\n", ExtendedTableCount));\r
+          } else {\r
             ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
             for (Index = 0; Index < ExtendedTableCount; Index++) {\r
-              CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
-              if (CheckSum32 == 0) {\r
+              CheckSum32 = InCompleteCheckSum32;\r
+              CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
+              CheckSum32 += ExtendedTable->ProcessorFlag;\r
+              CheckSum32 += ExtendedTable->Checksum;\r
+              if (CheckSum32 != 0) {\r
+                DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for ExtendedTable entry with index 0x%x is incorrect\n", Index));\r
+              } else {\r
                 //\r
                 // Verify Header\r
                 //\r
@@ -526,11 +554,11 @@ VerifyMicrocode (
     }\r
     if (!CorrectMicrocode) {\r
       if (TryLoad) {\r
-        DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));\r
+        DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on Current ProcessorSignature/ProcessorFlags\n"));\r
       }\r
       *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
       if (AbortReason != NULL) {\r
-        *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");\r
+        *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorSignature/ProcessorFlags"), L"UnsupportedProcessorSignature/ProcessorFlags");\r
       }\r
       return EFI_UNSUPPORTED;\r
     }\r
@@ -602,6 +630,124 @@ GetNextMicrocode (
   return NULL;\r
 }\r
 \r
+/**\r
+  Get next FIT Microcode entrypoint.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  MicrocodeEntryPoint        Current Microcode entrypoint\r
+\r
+  @return next FIT Microcode entrypoint.\r
+**/\r
+CPU_MICROCODE_HEADER *\r
+GetNextFitMicrocode (\r
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,\r
+  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint\r
+  )\r
+{\r
+  UINTN                                   Index;\r
+\r
+  for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
+    if (MicrocodeEntryPoint == MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint) {\r
+      if (Index == (UINTN) MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1) {\r
+        // it is last one\r
+        return NULL;\r
+      } else {\r
+        // return next one\r
+        return MicrocodeFmpPrivate->FitMicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
+      }\r
+    }\r
+  }\r
+\r
+  ASSERT(FALSE);\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Find empty FIT Microcode entrypoint.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.\r
+  @param[out] AvailableSize              Available size of the empty FIT Microcode entrypoint.\r
+\r
+  @return Empty FIT Microcode entrypoint.\r
+**/\r
+CPU_MICROCODE_HEADER *\r
+FindEmptyFitMicrocode (\r
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,\r
+  IN UINTN                                   ImageSize,\r
+  OUT UINTN                                  *AvailableSize\r
+  )\r
+{\r
+  UINTN                                   Index;\r
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;\r
+  CPU_MICROCODE_HEADER                    *NextMicrocodeEntryPoint;\r
+  VOID                                    *MicrocodePatchAddress;\r
+  UINTN                                   MicrocodePatchRegionSize;\r
+\r
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
+\r
+  for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
+    if (MicrocodeFmpPrivate->FitMicrocodeInfo[Index].Empty) {\r
+      MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
+      NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
+      if (NextMicrocodeEntryPoint != NULL) {\r
+        *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
+      } else {\r
+        *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
+      }\r
+      if (*AvailableSize >= ImageSize) {\r
+        return MicrocodeEntryPoint;\r
+      }\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Find unused FIT Microcode entrypoint.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.\r
+  @param[out] AvailableSize              Available size of the unused FIT Microcode entrypoint.\r
+\r
+  @return Unused FIT Microcode entrypoint.\r
+**/\r
+CPU_MICROCODE_HEADER *\r
+FindUnusedFitMicrocode (\r
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,\r
+  IN UINTN                                   ImageSize,\r
+  OUT UINTN                                  *AvailableSize\r
+  )\r
+{\r
+  UINTN                                   Index;\r
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;\r
+  CPU_MICROCODE_HEADER                    *NextMicrocodeEntryPoint;\r
+  VOID                                    *MicrocodePatchAddress;\r
+  UINTN                                   MicrocodePatchRegionSize;\r
+\r
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
+\r
+  for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
+    if (!MicrocodeFmpPrivate->FitMicrocodeInfo[Index].InUse) {\r
+      MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
+      NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
+      if (NextMicrocodeEntryPoint != NULL) {\r
+        *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
+      } else {\r
+        *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
+      }\r
+      if (*AvailableSize >= ImageSize) {\r
+        return MicrocodeEntryPoint;\r
+      }\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
 /**\r
   Get current Microcode used region size.\r
 \r
@@ -646,7 +792,7 @@ UpdateMicrocode (
 \r
   DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
   DEBUG((DEBUG_INFO, "  Address - 0x%lx,", Address));\r
-  DEBUG((DEBUG_INFO, "  Legnth - 0x%x\n", ImageSize));\r
+  DEBUG((DEBUG_INFO, "  Length - 0x%x\n", ImageSize));\r
 \r
   Status = MicrocodeFlashWrite (\r
              Address,\r
@@ -661,6 +807,201 @@ UpdateMicrocode (
   return Status;\r
 }\r
 \r
+/**\r
+  Update Microcode flash region with FIT.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  TargetMicrocodeEntryPoint  Target Microcode entrypoint to be updated\r
+  @param[in]  Image                      The Microcode image buffer.\r
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.\r
+  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+  @retval EFI_SUCCESS             The Microcode image is written.\r
+  @retval EFI_WRITE_PROTECTED     The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+UpdateMicrocodeFlashRegionWithFit (\r
+  IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,\r
+  IN  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint,\r
+  IN  VOID                                    *Image,\r
+  IN  UINTN                                   ImageSize,\r
+  OUT UINT32                                  *LastAttemptStatus\r
+  )\r
+{\r
+  VOID                                    *MicrocodePatchAddress;\r
+  UINTN                                   MicrocodePatchRegionSize;\r
+  UINTN                                   TargetTotalSize;\r
+  EFI_STATUS                              Status;\r
+  VOID                                    *MicrocodePatchScratchBuffer;\r
+  UINT8                                   *ScratchBufferPtr;\r
+  UINTN                                   ScratchBufferSize;\r
+  UINTN                                   RestSize;\r
+  UINTN                                   AvailableSize;\r
+  VOID                                    *NextMicrocodeEntryPoint;\r
+  VOID                                    *EmptyFitMicrocodeEntry;\r
+  VOID                                    *UnusedFitMicrocodeEntry;\r
+\r
+  DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegionWithFit: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
+\r
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
+\r
+  MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
+  if (MicrocodePatchScratchBuffer == NULL) {\r
+    DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
+  ScratchBufferSize = 0;\r
+\r
+  //\r
+  // Target data collection\r
+  //\r
+  TargetTotalSize = 0;\r
+  AvailableSize = 0;\r
+  if (TargetMicrocodeEntryPoint != NULL) {\r
+    if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
+      TargetTotalSize = 2048;\r
+    } else {\r
+      TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
+    }\r
+    DEBUG((DEBUG_INFO, "  TargetTotalSize - 0x%x\n", TargetTotalSize));\r
+    NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
+    DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
+    if (NextMicrocodeEntryPoint != NULL) {\r
+      ASSERT ((UINTN) NextMicrocodeEntryPoint >= ((UINTN) TargetMicrocodeEntryPoint + TargetTotalSize));\r
+      AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) TargetMicrocodeEntryPoint;\r
+    } else {\r
+      AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) TargetMicrocodeEntryPoint;\r
+    }\r
+    DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));\r
+    ASSERT (AvailableSize >= TargetTotalSize);\r
+  }\r
+  //\r
+  // Total Size means the Microcode size.\r
+  // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
+  //\r
+  // (1)\r
+  // +------+-----------+-----+------+===================+\r
+  // | MCU1 | Microcode | PAD | MCU2 |      Empty        |\r
+  // +------+-----------+-----+------+===================+\r
+  //        | TotalSize |\r
+  //        |<-AvailableSize->|\r
+  //\r
+  // (2)\r
+  // +------+-----------+===================+\r
+  // | MCU  | Microcode |      Empty        |\r
+  // +------+-----------+===================+\r
+  //        | TotalSize |\r
+  //        |<-      AvailableSize        ->|\r
+  //\r
+\r
+  //\r
+  // Update based on policy\r
+  //\r
+\r
+  //\r
+  // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
+  //\r
+  if (AvailableSize >= ImageSize) {\r
+    DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
+    //\r
+    // +------+------------+------+===================+\r
+    // |Other | Old Image  | ...  |      Empty        |\r
+    // +------+------------+------+===================+\r
+    //\r
+    // +------+---------+--+------+===================+\r
+    // |Other |New Image|FF| ...  |      Empty        |\r
+    // +------+---------+--+------+===================+\r
+    //\r
+    // 1.1. Copy new image\r
+    CopyMem (ScratchBufferPtr, Image, ImageSize);\r
+    ScratchBufferSize += ImageSize;\r
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    // 1.2. Pad 0xFF\r
+    RestSize = AvailableSize - ImageSize;\r
+    if (RestSize > 0) {\r
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
+      ScratchBufferSize += RestSize;\r
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    }\r
+    Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // 2. If there is empty FIT microcode entry with enough space, use it.\r
+  //\r
+  EmptyFitMicrocodeEntry = FindEmptyFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
+  if (EmptyFitMicrocodeEntry != NULL) {\r
+    DEBUG((DEBUG_INFO, "Use empty FIT microcode entry\n"));\r
+    // 2.1. Copy new image\r
+    CopyMem (ScratchBufferPtr, Image, ImageSize);\r
+    ScratchBufferSize += ImageSize;\r
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    // 2.2. Pad 0xFF\r
+    RestSize = AvailableSize - ImageSize;\r
+    if (RestSize > 0) {\r
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
+      ScratchBufferSize += RestSize;\r
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    }\r
+    Status = UpdateMicrocode ((UINTN) EmptyFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
+      //\r
+      // Empty old microcode.\r
+      //\r
+      ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
+      SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
+      ScratchBufferSize = TargetTotalSize;\r
+      ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+      UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // 3. If there is unused microcode entry with enough space, use it.\r
+  //\r
+  UnusedFitMicrocodeEntry = FindUnusedFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
+  if (UnusedFitMicrocodeEntry != NULL) {\r
+    DEBUG((DEBUG_INFO, "Use unused FIT microcode entry\n"));\r
+    // 3.1. Copy new image\r
+    CopyMem (ScratchBufferPtr, Image, ImageSize);\r
+    ScratchBufferSize += ImageSize;\r
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    // 3.2. Pad 0xFF\r
+    RestSize = AvailableSize - ImageSize;\r
+    if (RestSize > 0) {\r
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
+      ScratchBufferSize += RestSize;\r
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    }\r
+    Status = UpdateMicrocode ((UINTN) UnusedFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
+      //\r
+      // Empty old microcode.\r
+      //\r
+      ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
+      SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
+      ScratchBufferSize = TargetTotalSize;\r
+      ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+      UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // 4. No usable FIT microcode entry.\r
+  //\r
+  DEBUG((DEBUG_ERROR, "No usable FIT microcode entry\n"));\r
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
+  Status = EFI_OUT_OF_RESOURCES;\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Update Microcode flash region.\r
 \r
@@ -733,8 +1074,8 @@ UpdateMicrocodeFlashRegion (
       AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
     }\r
     DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));\r
+    ASSERT (AvailableSize >= TargetTotalSize);\r
   }\r
-  ASSERT (AvailableSize >= TargetTotalSize);\r
   UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
   DEBUG((DEBUG_INFO, "  UsedRegionSize - 0x%x\n", UsedRegionSize));\r
   ASSERT (UsedRegionSize >= TargetTotalSize);\r
@@ -742,8 +1083,8 @@ UpdateMicrocodeFlashRegion (
     ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
   }\r
   //\r
-  // Total Size means the Microcode data size.\r
-  // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.\r
+  // Total Size means the Microcode size.\r
+  // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
   //\r
   // (1)\r
   // +------+-----------+-----+------+===================+\r
@@ -773,11 +1114,11 @@ UpdateMicrocodeFlashRegion (
     DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
     //\r
     // +------+------------+------+===================+\r
-    // |Other1| Old Image  |Other2|      Empty        |\r
+    // |Other | Old Image  | ...  |      Empty        |\r
     // +------+------------+------+===================+\r
     //\r
     // +------+---------+--+------+===================+\r
-    // |Other1|New Image|FF|Other2|      Empty        |\r
+    // |Other |New Image|FF| ...  |      Empty        |\r
     // +------+---------+--+------+===================+\r
     //\r
     // 1.1. Copy new image\r
@@ -815,11 +1156,11 @@ UpdateMicrocodeFlashRegion (
       DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
       //\r
       // +------+------------+------+===================+\r
-      // |Other1| Old Image  |Other2|      Empty        |\r
+      // |Other | Old Image  | ...  |      Empty        |\r
       // +------+------------+------+===================+\r
       //\r
       // +------+---------------+------+================+\r
-      // |Other1|   New Image   |Other2|      Empty     |\r
+      // |Other |   New Image   | ...  |      Empty     |\r
       // +------+---------------+------+================+\r
       //\r
       // 2.1. Copy new image\r
@@ -829,7 +1170,7 @@ UpdateMicrocodeFlashRegion (
       // 2.2. Copy rest images after the old image.\r
       if (NextMicrocodeEntryPoint != 0) {\r
         RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
-        CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);\r
+        CopyMem (ScratchBufferPtr, NextMicrocodeEntryPoint, RestSize);\r
         ScratchBufferSize += RestSize;\r
         ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
       }\r
@@ -912,7 +1253,7 @@ UpdateMicrocodeFlashRegion (
                                    call to FreePool().\r
 \r
   @retval EFI_SUCCESS               The Microcode image is written.\r
-  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.\r
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupted.\r
   @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.\r
   @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.\r
   @retval EFI_WRITE_PROTECTED       The flash device is read only.\r
@@ -943,7 +1284,6 @@ MicrocodeWrite (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
   TargetCpuIndex = (UINTN)-1;\r
   Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
   if (EFI_ERROR(Status)) {\r
@@ -952,6 +1292,7 @@ MicrocodeWrite (
     return Status;\r
   }\r
   DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));\r
+  *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
 \r
   DEBUG((DEBUG_INFO, "  TargetCpuIndex - 0x%x\n", TargetCpuIndex));\r
   ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
@@ -965,13 +1306,23 @@ MicrocodeWrite (
   }\r
   DEBUG((DEBUG_INFO, "  TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
 \r
-  Status = UpdateMicrocodeFlashRegion(\r
-             MicrocodeFmpPrivate,\r
-             TargetMicrocodeEntryPoint,\r
-             AlignedImage,\r
-             ImageSize,\r
-             LastAttemptStatus\r
-             );\r
+  if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
+    Status = UpdateMicrocodeFlashRegionWithFit (\r
+               MicrocodeFmpPrivate,\r
+               TargetMicrocodeEntryPoint,\r
+               AlignedImage,\r
+               ImageSize,\r
+               LastAttemptStatus\r
+               );\r
+  } else {\r
+    Status = UpdateMicrocodeFlashRegion (\r
+               MicrocodeFmpPrivate,\r
+               TargetMicrocodeEntryPoint,\r
+               AlignedImage,\r
+               ImageSize,\r
+               LastAttemptStatus\r
+               );\r
+  }\r
 \r
   FreePool(AlignedImage);\r
 \r