Home | History | Annotate | Download | only in MicrocodeUpdateDxe
      1 /** @file
      2   SetImage instance to update Microcode.
      3 
      4   Caution: This module requires additional review when modified.
      5   This module will have external input - capsule image.
      6   This external input must be validated carefully to avoid security issue like
      7   buffer overflow, integer overflow.
      8 
      9   MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.
     10 
     11   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
     12   This program and the accompanying materials
     13   are licensed and made available under the terms and conditions of the BSD License
     14   which accompanies this distribution.  The full text of the license may be found at
     15   http://opensource.org/licenses/bsd-license.php
     16 
     17   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     19 
     20 **/
     21 
     22 #include "MicrocodeUpdate.h"
     23 
     24 /**
     25   Get Microcode Region.
     26 
     27   @param[out] MicrocodePatchAddress      The address of Microcode
     28   @param[out] MicrocodePatchRegionSize   The region size of Microcode
     29 
     30   @retval TRUE   The Microcode region is returned.
     31   @retval FALSE  No Microcode region.
     32 **/
     33 BOOLEAN
     34 GetMicrocodeRegion (
     35   OUT VOID     **MicrocodePatchAddress,
     36   OUT UINTN    *MicrocodePatchRegionSize
     37   )
     38 {
     39   *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);
     40   *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);
     41 
     42   if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {
     43     return FALSE;
     44   }
     45 
     46   return TRUE;
     47 }
     48 
     49 /**
     50   Get Microcode update signature of currently loaded Microcode update.
     51 
     52   @return  Microcode signature.
     53 
     54 **/
     55 UINT32
     56 GetCurrentMicrocodeSignature (
     57   VOID
     58   )
     59 {
     60   UINT64 Signature;
     61 
     62   AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);
     63   AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
     64   Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);
     65   return (UINT32)RShiftU64(Signature, 32);
     66 }
     67 
     68 /**
     69   Get current processor signature.
     70 
     71   @return current processor signature.
     72 **/
     73 UINT32
     74 GetCurrentProcessorSignature (
     75   VOID
     76   )
     77 {
     78   UINT32                                  RegEax;
     79   AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
     80   return RegEax;
     81 }
     82 
     83 /**
     84   Get current platform ID.
     85 
     86   @return current platform ID.
     87 **/
     88 UINT8
     89 GetCurrentPlatformId (
     90   VOID
     91   )
     92 {
     93   UINT8                                   PlatformId;
     94 
     95   PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);
     96   return PlatformId;
     97 }
     98 
     99 /**
    100   Load new Microcode.
    101 
    102   @param[in] Address  The address of new Microcode.
    103 
    104   @return  Loaded Microcode signature.
    105 
    106 **/
    107 UINT32
    108 LoadMicrocode (
    109   IN UINT64  Address
    110   )
    111 {
    112   AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);
    113   return GetCurrentMicrocodeSignature();
    114 }
    115 
    116 /**
    117   Load Microcode on an Application Processor.
    118   The function prototype for invoking a function on an Application Processor.
    119 
    120   @param[in,out] Buffer  The pointer to private data buffer.
    121 **/
    122 VOID
    123 EFIAPI
    124 MicrocodeLoadAp (
    125   IN OUT VOID  *Buffer
    126   )
    127 {
    128   MICROCODE_LOAD_BUFFER                *MicrocodeLoadBuffer;
    129 
    130   MicrocodeLoadBuffer = Buffer;
    131   MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);
    132 }
    133 
    134 /**
    135   Load new Microcode on this processor
    136 
    137   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
    138   @param[in]  CpuIndex                   The index of the processor.
    139   @param[in]  Address                    The address of new Microcode.
    140 
    141   @return  Loaded Microcode signature.
    142 
    143 **/
    144 UINT32
    145 LoadMicrocodeOnThis (
    146   IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
    147   IN  UINTN                       CpuIndex,
    148   IN  UINT64                      Address
    149   )
    150 {
    151   EFI_STATUS                           Status;
    152   EFI_MP_SERVICES_PROTOCOL             *MpService;
    153   MICROCODE_LOAD_BUFFER                MicrocodeLoadBuffer;
    154 
    155   if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {
    156     return LoadMicrocode (Address);
    157   } else {
    158     MpService = MicrocodeFmpPrivate->MpService;
    159     MicrocodeLoadBuffer.Address = Address;
    160     MicrocodeLoadBuffer.Revision = 0;
    161     Status = MpService->StartupThisAP (
    162                           MpService,
    163                           MicrocodeLoadAp,
    164                           CpuIndex,
    165                           NULL,
    166                           0,
    167                           &MicrocodeLoadBuffer,
    168                           NULL
    169                           );
    170     ASSERT_EFI_ERROR(Status);
    171     return MicrocodeLoadBuffer.Revision;
    172   }
    173 }
    174 
    175 /**
    176   Collect processor information.
    177   The function prototype for invoking a function on an Application Processor.
    178 
    179   @param[in,out] Buffer  The pointer to private data buffer.
    180 **/
    181 VOID
    182 EFIAPI
    183 CollectProcessorInfo (
    184   IN OUT VOID  *Buffer
    185   )
    186 {
    187   PROCESSOR_INFO  *ProcessorInfo;
    188 
    189   ProcessorInfo = Buffer;
    190   ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();
    191   ProcessorInfo->PlatformId = GetCurrentPlatformId();
    192   ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();
    193 }
    194 
    195 /**
    196   Get current Microcode information.
    197 
    198   The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
    199   in MicrocodeFmpPrivate must be initialized.
    200 
    201   The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
    202   in MicrocodeFmpPrivate may not be avaiable in this function.
    203 
    204   @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
    205   @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
    206   @param[out]  ImageDescriptor            Microcode ImageDescriptor
    207   @param[out]  MicrocodeInfo              Microcode information
    208 
    209   @return Microcode count
    210 **/
    211 UINTN
    212 GetMicrocodeInfo (
    213   IN  MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate,
    214   IN  UINTN                          DescriptorCount,  OPTIONAL
    215   OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL
    216   OUT MICROCODE_INFO                 *MicrocodeInfo    OPTIONAL
    217   )
    218 {
    219   VOID                                    *MicrocodePatchAddress;
    220   UINTN                                   MicrocodePatchRegionSize;
    221   CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
    222   UINTN                                   MicrocodeEnd;
    223   UINTN                                   TotalSize;
    224   UINTN                                   Count;
    225   UINT64                                  ImageAttributes;
    226   BOOLEAN                                 IsInUse;
    227   EFI_STATUS                              Status;
    228   UINT32                                  AttemptStatus;
    229   UINTN                                   TargetCpuIndex;
    230 
    231   MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
    232   MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
    233 
    234   DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));
    235 
    236   Count = 0;
    237 
    238   MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;
    239   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
    240   do {
    241     if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {
    242       //
    243       // It is the microcode header. It is not the padding data between microcode patches
    244       // becasue the padding data should not include 0x00000001 and it should be the repeated
    245       // byte format (like 0xXYXYXYXY....).
    246       //
    247       if (MicrocodeEntryPoint->DataSize == 0) {
    248         TotalSize = 2048;
    249       } else {
    250         TotalSize = MicrocodeEntryPoint->TotalSize;
    251       }
    252 
    253       TargetCpuIndex = (UINTN)-1;
    254       Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);
    255       if (!EFI_ERROR(Status)) {
    256         IsInUse = TRUE;
    257         ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
    258         MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;
    259       } else {
    260         IsInUse = FALSE;
    261       }
    262 
    263       if (ImageDescriptor != NULL && DescriptorCount > Count) {
    264         ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);
    265         CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);
    266         ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;
    267         ImageDescriptor[Count].ImageIdName = NULL;
    268         ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;
    269         ImageDescriptor[Count].VersionName = NULL;
    270         ImageDescriptor[Count].Size = TotalSize;
    271         ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;
    272         if (IsInUse) {
    273           ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;
    274         }
    275         ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;
    276         ImageDescriptor[Count].AttributesSetting = ImageAttributes;
    277         ImageDescriptor[Count].Compatibilities = 0;
    278         ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback
    279         ImageDescriptor[Count].LastAttemptVersion = 0;
    280         ImageDescriptor[Count].LastAttemptStatus = 0;
    281         ImageDescriptor[Count].HardwareInstance = 0;
    282       }
    283       if (MicrocodeInfo != NULL && DescriptorCount > Count) {
    284         MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;
    285         MicrocodeInfo[Count].TotalSize = TotalSize;
    286         MicrocodeInfo[Count].InUse = IsInUse;
    287       }
    288     } else {
    289       //
    290       // It is the padding data between the microcode patches for microcode patches alignment.
    291       // Because the microcode patch is the multiple of 1-KByte, the padding data should not
    292       // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
    293       // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
    294       // find the next possible microcode patch header.
    295       //
    296       MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
    297       continue;
    298     }
    299 
    300     Count++;
    301     ASSERT(Count < 0xFF);
    302 
    303     //
    304     // Get the next patch.
    305     //
    306     MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
    307   } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
    308 
    309   return Count;
    310 }
    311 
    312 /**
    313   Return matched processor information.
    314 
    315   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
    316   @param[in]  ProcessorSignature         The processor signature to be matched
    317   @param[in]  ProcessorFlags             The processor flags to be matched
    318   @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
    319                                          On output, the index of target CPU which matches the Microcode.
    320 
    321   @return matched processor information.
    322 **/
    323 PROCESSOR_INFO *
    324 GetMatchedProcessor (
    325   IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
    326   IN UINT32                      ProcessorSignature,
    327   IN UINT32                      ProcessorFlags,
    328   IN OUT UINTN                   *TargetCpuIndex
    329   )
    330 {
    331   UINTN  Index;
    332 
    333   if (*TargetCpuIndex != (UINTN)-1) {
    334     Index = *TargetCpuIndex;
    335     if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
    336         ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
    337       return &MicrocodeFmpPrivate->ProcessorInfo[Index];
    338     } else {
    339       return NULL;
    340     }
    341   }
    342 
    343   for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
    344     if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
    345         ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
    346       *TargetCpuIndex = Index;
    347       return &MicrocodeFmpPrivate->ProcessorInfo[Index];
    348     }
    349   }
    350   return NULL;
    351 }
    352 
    353 /**
    354   Verify Microcode.
    355 
    356   Caution: This function may receive untrusted input.
    357 
    358   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
    359   @param[in]  Image                      The Microcode image buffer.
    360   @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
    361   @param[in]  TryLoad                    Try to load Microcode or not.
    362   @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
    363   @param[out] AbortReason                A pointer to a pointer to a null-terminated string providing more
    364                                          details for the aborted operation. The buffer is allocated by this function
    365                                          with AllocatePool(), and it is the caller's responsibility to free it with a
    366                                          call to FreePool().
    367   @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
    368                                          On output, the index of target CPU which matches the Microcode.
    369 
    370   @retval EFI_SUCCESS               The Microcode image passes verification.
    371   @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.
    372   @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
    373   @retval EFI_UNSUPPORTED           The Microcode ProcessorSignature or ProcessorFlags is incorrect.
    374   @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
    375 **/
    376 EFI_STATUS
    377 VerifyMicrocode (
    378   IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
    379   IN  VOID                        *Image,
    380   IN  UINTN                       ImageSize,
    381   IN  BOOLEAN                     TryLoad,
    382   OUT UINT32                      *LastAttemptStatus,
    383   OUT CHAR16                      **AbortReason,   OPTIONAL
    384   IN OUT UINTN                    *TargetCpuIndex
    385   )
    386 {
    387   UINTN                                   Index;
    388   CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
    389   UINTN                                   TotalSize;
    390   UINTN                                   DataSize;
    391   UINT32                                  CurrentRevision;
    392   PROCESSOR_INFO                          *ProcessorInfo;
    393   UINT32                                  CheckSum32;
    394   UINTN                                   ExtendedTableLength;
    395   UINT32                                  ExtendedTableCount;
    396   CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;
    397   CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;
    398   BOOLEAN                                 CorrectMicrocode;
    399 
    400   //
    401   // Check HeaderVersion
    402   //
    403   MicrocodeEntryPoint = Image;
    404   if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
    405     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));
    406     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
    407     if (AbortReason != NULL) {
    408       *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");
    409     }
    410     return EFI_INCOMPATIBLE_VERSION;
    411   }
    412   //
    413   // Check LoaderRevision
    414   //
    415   if (MicrocodeEntryPoint->LoaderRevision != 0x1) {
    416     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));
    417     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
    418     if (AbortReason != NULL) {
    419       *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");
    420     }
    421     return EFI_INCOMPATIBLE_VERSION;
    422   }
    423   //
    424   // Check Size
    425   //
    426   if (MicrocodeEntryPoint->DataSize == 0) {
    427     TotalSize = 2048;
    428   } else {
    429     TotalSize = MicrocodeEntryPoint->TotalSize;
    430   }
    431   if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {
    432     DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));
    433     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
    434     if (AbortReason != NULL) {
    435       *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
    436     }
    437     return EFI_VOLUME_CORRUPTED;
    438   }
    439   if (TotalSize != ImageSize) {
    440     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\n"));
    441     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
    442     if (AbortReason != NULL) {
    443       *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
    444     }
    445     return EFI_VOLUME_CORRUPTED;
    446   }
    447   //
    448   // Check CheckSum32
    449   //
    450   if (MicrocodeEntryPoint->DataSize == 0) {
    451     DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);
    452   } else {
    453     DataSize = MicrocodeEntryPoint->DataSize;
    454   }
    455   if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {
    456     DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));
    457     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
    458     if (AbortReason != NULL) {
    459       *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
    460     }
    461     return EFI_VOLUME_CORRUPTED;
    462   }
    463   if ((DataSize & 0x3) != 0) {
    464     DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize not aligned\n"));
    465     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
    466     if (AbortReason != NULL) {
    467       *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
    468     }
    469     return EFI_VOLUME_CORRUPTED;
    470   }
    471   CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));
    472   if (CheckSum32 != 0) {
    473     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));
    474     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
    475     if (AbortReason != NULL) {
    476       *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");
    477     }
    478     return EFI_VOLUME_CORRUPTED;
    479   }
    480 
    481   //
    482   // Check ProcessorSignature/ProcessorFlags
    483   //
    484 
    485   ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);
    486   if (ProcessorInfo == NULL) {
    487     CorrectMicrocode = FALSE;
    488     ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));
    489     if (ExtendedTableLength != 0) {
    490       //
    491       // Extended Table exist, check if the CPU in support list
    492       //
    493       ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));
    494       //
    495       // Calculate Extended Checksum
    496       //
    497       if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) != 0)) {
    498         CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
    499         if (CheckSum32 == 0) {
    500           //
    501           // Checksum correct
    502           //
    503           ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
    504           if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {
    505             ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
    506             for (Index = 0; Index < ExtendedTableCount; Index++) {
    507               CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));
    508               if (CheckSum32 == 0) {
    509                 //
    510                 // Verify Header
    511                 //
    512                 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);
    513                 if (ProcessorInfo != NULL) {
    514                   //
    515                   // Find one
    516                   //
    517                   CorrectMicrocode = TRUE;
    518                   break;
    519                 }
    520               }
    521               ExtendedTable++;
    522             }
    523           }
    524         }
    525       }
    526     }
    527     if (!CorrectMicrocode) {
    528       if (TryLoad) {
    529         DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
    530       }
    531       *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
    532       if (AbortReason != NULL) {
    533         *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");
    534       }
    535       return EFI_UNSUPPORTED;
    536     }
    537   }
    538 
    539   //
    540   // Check UpdateRevision
    541   //
    542   CurrentRevision = ProcessorInfo->MicrocodeRevision;
    543   if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||
    544       (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {
    545     if (TryLoad) {
    546       DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));
    547     }
    548     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
    549     if (AbortReason != NULL) {
    550       *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");
    551     }
    552     return EFI_INCOMPATIBLE_VERSION;
    553   }
    554 
    555   //
    556   // try load MCU
    557   //
    558   if (TryLoad) {
    559     CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));
    560     if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {
    561       DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));
    562       *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
    563       if (AbortReason != NULL) {
    564         *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");
    565       }
    566       return EFI_SECURITY_VIOLATION;
    567     }
    568   }
    569 
    570   return EFI_SUCCESS;
    571 }
    572 
    573 /**
    574   Get next Microcode entrypoint.
    575 
    576   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
    577   @param[in]  MicrocodeEntryPoint        Current Microcode entrypoint
    578 
    579   @return next Microcode entrypoint.
    580 **/
    581 CPU_MICROCODE_HEADER *
    582 GetNextMicrocode (
    583   IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
    584   IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint
    585   )
    586 {
    587   UINTN                                   Index;
    588 
    589   for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
    590     if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {
    591       if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {
    592         // it is last one
    593         return NULL;
    594       } else {
    595         // return next one
    596         return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;
    597       }
    598     }
    599   }
    600 
    601   ASSERT(FALSE);
    602   return NULL;
    603 }
    604 
    605 /**
    606   Get current Microcode used region size.
    607 
    608   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
    609 
    610   @return current Microcode used region size.
    611 **/
    612 UINTN
    613 GetCurrentMicrocodeUsedRegionSize (
    614   IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate
    615   )
    616 {
    617   if (MicrocodeFmpPrivate->DescriptorCount == 0) {
    618     return 0;
    619   }
    620 
    621   return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint
    622          + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize
    623          - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;
    624 }
    625 
    626 /**
    627   Update Microcode.
    628 
    629   @param[in]   Address            The flash address of Microcode.
    630   @param[in]   Image              The Microcode image buffer.
    631   @param[in]   ImageSize          The size of Microcode image buffer in bytes.
    632   @param[out]  LastAttemptStatus  The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
    633 
    634   @retval EFI_SUCCESS           The Microcode image is updated.
    635   @retval EFI_WRITE_PROTECTED   The flash device is read only.
    636 **/
    637 EFI_STATUS
    638 UpdateMicrocode (
    639   IN UINT64   Address,
    640   IN VOID     *Image,
    641   IN UINTN    ImageSize,
    642   OUT UINT32  *LastAttemptStatus
    643   )
    644 {
    645   EFI_STATUS  Status;
    646 
    647   DEBUG((DEBUG_INFO, "PlatformUpdate:"));
    648   DEBUG((DEBUG_INFO, "  Address - 0x%lx,", Address));
    649   DEBUG((DEBUG_INFO, "  Legnth - 0x%x\n", ImageSize));
    650 
    651   Status = MicrocodeFlashWrite (
    652              Address,
    653              Image,
    654              ImageSize
    655              );
    656   if (!EFI_ERROR(Status)) {
    657     *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
    658   } else {
    659     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
    660   }
    661   return Status;
    662 }
    663 
    664 /**
    665   Update Microcode flash region.
    666 
    667   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
    668   @param[in]  TargetMicrocodeEntryPoint  Target Microcode entrypoint to be updated
    669   @param[in]  Image                      The Microcode image buffer.
    670   @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
    671   @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
    672 
    673   @retval EFI_SUCCESS             The Microcode image is written.
    674   @retval EFI_WRITE_PROTECTED     The flash device is read only.
    675 **/
    676 EFI_STATUS
    677 UpdateMicrocodeFlashRegion (
    678   IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
    679   IN  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint,
    680   IN  VOID                                    *Image,
    681   IN  UINTN                                   ImageSize,
    682   OUT UINT32                                  *LastAttemptStatus
    683   )
    684 {
    685   VOID                                    *MicrocodePatchAddress;
    686   UINTN                                   MicrocodePatchRegionSize;
    687   UINTN                                   TargetTotalSize;
    688   UINTN                                   UsedRegionSize;
    689   EFI_STATUS                              Status;
    690   VOID                                    *MicrocodePatchScratchBuffer;
    691   UINT8                                   *ScratchBufferPtr;
    692   UINTN                                   ScratchBufferSize;
    693   UINTN                                   RestSize;
    694   UINTN                                   AvailableSize;
    695   VOID                                    *NextMicrocodeEntryPoint;
    696   MICROCODE_INFO                          *MicrocodeInfo;
    697   UINTN                                   MicrocodeCount;
    698   UINTN                                   Index;
    699 
    700   DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));
    701 
    702   MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
    703   MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
    704 
    705   MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);
    706   if (MicrocodePatchScratchBuffer == NULL) {
    707     DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));
    708     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
    709     return EFI_OUT_OF_RESOURCES;
    710   }
    711   ScratchBufferPtr = MicrocodePatchScratchBuffer;
    712   ScratchBufferSize = 0;
    713 
    714   //
    715   // Target data collection
    716   //
    717   TargetTotalSize = 0;
    718   AvailableSize = 0;
    719   NextMicrocodeEntryPoint = NULL;
    720   if (TargetMicrocodeEntryPoint != NULL) {
    721     if (TargetMicrocodeEntryPoint->DataSize == 0) {
    722       TargetTotalSize = 2048;
    723     } else {
    724       TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;
    725     }
    726     DEBUG((DEBUG_INFO, "  TargetTotalSize - 0x%x\n", TargetTotalSize));
    727     NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);
    728     DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
    729     if (NextMicrocodeEntryPoint != NULL) {
    730       ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
    731       AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;
    732     } else {
    733       AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;
    734     }
    735     DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));
    736   }
    737   ASSERT (AvailableSize >= TargetTotalSize);
    738   UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);
    739   DEBUG((DEBUG_INFO, "  UsedRegionSize - 0x%x\n", UsedRegionSize));
    740   ASSERT (UsedRegionSize >= TargetTotalSize);
    741   if (TargetMicrocodeEntryPoint != NULL) {
    742     ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
    743   }
    744   //
    745   // Total Size means the Microcode data size.
    746   // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.
    747   //
    748   // (1)
    749   // +------+-----------+-----+------+===================+
    750   // | MCU1 | Microcode | PAD | MCU2 |      Empty        |
    751   // +------+-----------+-----+------+===================+
    752   //        | TotalSize |
    753   //        |<-AvailableSize->|
    754   // |<-        UsedRegionSize     ->|
    755   //
    756   // (2)
    757   // +------+-----------+===================+
    758   // | MCU  | Microcode |      Empty        |
    759   // +------+-----------+===================+
    760   //        | TotalSize |
    761   //        |<-      AvailableSize        ->|
    762   // |<-UsedRegionSize->|
    763   //
    764 
    765   //
    766   // Update based on policy
    767   //
    768 
    769   //
    770   // 1. If there is enough space to update old one in situ, replace old microcode in situ.
    771   //
    772   if (AvailableSize >= ImageSize) {
    773     DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));
    774     //
    775     // +------+------------+------+===================+
    776     // |Other1| Old Image  |Other2|      Empty        |
    777     // +------+------------+------+===================+
    778     //
    779     // +------+---------+--+------+===================+
    780     // |Other1|New Image|FF|Other2|      Empty        |
    781     // +------+---------+--+------+===================+
    782     //
    783     // 1.1. Copy new image
    784     CopyMem (ScratchBufferPtr, Image, ImageSize);
    785     ScratchBufferSize += ImageSize;
    786     ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
    787     // 1.2. Pad 0xFF
    788     RestSize = AvailableSize - ImageSize;
    789     if (RestSize > 0) {
    790       SetMem (ScratchBufferPtr, RestSize, 0xFF);
    791       ScratchBufferSize += RestSize;
    792       ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
    793     }
    794     Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
    795     return Status;
    796   }
    797 
    798   //
    799   // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
    800   //
    801   if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {
    802     if (TargetMicrocodeEntryPoint == NULL) {
    803       DEBUG((DEBUG_INFO, "Append new microcode\n"));
    804       //
    805       // +------+------------+------+===================+
    806       // |Other1|   Other    |Other2|      Empty        |
    807       // +------+------------+------+===================+
    808       //
    809       // +------+------------+------+-----------+=======+
    810       // |Other1|   Other    |Other2| New Image | Empty |
    811       // +------+------------+------+-----------+=======+
    812       //
    813       Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);
    814     } else {
    815       DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));
    816       //
    817       // +------+------------+------+===================+
    818       // |Other1| Old Image  |Other2|      Empty        |
    819       // +------+------------+------+===================+
    820       //
    821       // +------+---------------+------+================+
    822       // |Other1|   New Image   |Other2|      Empty     |
    823       // +------+---------------+------+================+
    824       //
    825       // 2.1. Copy new image
    826       CopyMem (ScratchBufferPtr, Image, ImageSize);
    827       ScratchBufferSize += ImageSize;
    828       ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
    829       // 2.2. Copy rest images after the old image.
    830       if (NextMicrocodeEntryPoint != 0) {
    831         RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);
    832         CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);
    833         ScratchBufferSize += RestSize;
    834         ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
    835       }
    836       Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
    837     }
    838     return Status;
    839   }
    840 
    841   //
    842   // 3. The new image can be put in MCU region, but not all others can be put.
    843   //    So all the unused MCU is removed.
    844   //
    845   if (MicrocodePatchRegionSize >= ImageSize) {
    846     //
    847     // +------+------------+------+===================+
    848     // |Other1| Old Image  |Other2|      Empty        |
    849     // +------+------------+------+===================+
    850     //
    851     // +-------------------------------------+--------+
    852     // |        New Image                    | Other  |
    853     // +-------------------------------------+--------+
    854     //
    855     DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));
    856 
    857     MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;
    858     MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
    859 
    860     // 3.1. Copy new image
    861     CopyMem (ScratchBufferPtr, Image, ImageSize);
    862     ScratchBufferSize += ImageSize;
    863     ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
    864     // 3.2. Copy some others to rest buffer
    865     for (Index = 0; Index < MicrocodeCount; Index++) {
    866       if (!MicrocodeInfo[Index].InUse) {
    867         continue;
    868       }
    869       if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {
    870         continue;
    871       }
    872       if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {
    873         CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);
    874         ScratchBufferSize += MicrocodeInfo[Index].TotalSize;
    875         ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
    876       }
    877     }
    878     // 3.3. Pad 0xFF
    879     RestSize = MicrocodePatchRegionSize - ScratchBufferSize;
    880     if (RestSize > 0) {
    881       SetMem (ScratchBufferPtr, RestSize, 0xFF);
    882       ScratchBufferSize += RestSize;
    883       ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
    884     }
    885     Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
    886     return Status;
    887   }
    888 
    889   //
    890   // 4. The new image size is bigger than the whole MCU region.
    891   //
    892   DEBUG((DEBUG_ERROR, "Microcode too big\n"));
    893   *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
    894   Status = EFI_OUT_OF_RESOURCES;
    895 
    896   return Status;
    897 }
    898 
    899 /**
    900   Write Microcode.
    901 
    902   Caution: This function may receive untrusted input.
    903 
    904   @param[in]   MicrocodeFmpPrivate The Microcode driver private data
    905   @param[in]   Image               The Microcode image buffer.
    906   @param[in]   ImageSize           The size of Microcode image buffer in bytes.
    907   @param[out]  LastAttemptVersion  The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
    908   @param[out]  LastAttemptStatus   The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
    909   @param[out]  AbortReason         A pointer to a pointer to a null-terminated string providing more
    910                                    details for the aborted operation. The buffer is allocated by this function
    911                                    with AllocatePool(), and it is the caller's responsibility to free it with a
    912                                    call to FreePool().
    913 
    914   @retval EFI_SUCCESS               The Microcode image is written.
    915   @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.
    916   @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
    917   @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
    918   @retval EFI_WRITE_PROTECTED       The flash device is read only.
    919 **/
    920 EFI_STATUS
    921 MicrocodeWrite (
    922   IN  MICROCODE_FMP_PRIVATE_DATA   *MicrocodeFmpPrivate,
    923   IN  VOID                         *Image,
    924   IN  UINTN                        ImageSize,
    925   OUT UINT32                       *LastAttemptVersion,
    926   OUT UINT32                       *LastAttemptStatus,
    927   OUT CHAR16                       **AbortReason
    928   )
    929 {
    930   EFI_STATUS                              Status;
    931   VOID                                    *AlignedImage;
    932   CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint;
    933   UINTN                                   TargetCpuIndex;
    934   UINTN                                   TargetMicrcodeIndex;
    935 
    936   //
    937   // MCU must be 16 bytes aligned
    938   //
    939   AlignedImage = AllocateCopyPool(ImageSize, Image);
    940   if (AlignedImage == NULL) {
    941     DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));
    942     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
    943     return EFI_OUT_OF_RESOURCES;
    944   }
    945 
    946   *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;
    947   TargetCpuIndex = (UINTN)-1;
    948   Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);
    949   if (EFI_ERROR(Status)) {
    950     DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));
    951     FreePool(AlignedImage);
    952     return Status;
    953   }
    954   DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));
    955 
    956   DEBUG((DEBUG_INFO, "  TargetCpuIndex - 0x%x\n", TargetCpuIndex));
    957   ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
    958   TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;
    959   DEBUG((DEBUG_INFO, "  TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));
    960   if (TargetMicrcodeIndex != (UINTN)-1) {
    961     ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);
    962     TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;
    963   } else {
    964     TargetMicrocodeEntryPoint = NULL;
    965   }
    966   DEBUG((DEBUG_INFO, "  TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));
    967 
    968   Status = UpdateMicrocodeFlashRegion(
    969              MicrocodeFmpPrivate,
    970              TargetMicrocodeEntryPoint,
    971              AlignedImage,
    972              ImageSize,
    973              LastAttemptStatus
    974              );
    975 
    976   FreePool(AlignedImage);
    977 
    978   return Status;
    979 }
    980 
    981 
    982