From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id C884A818F0 for ; Tue, 27 Dec 2016 17:37:38 -0800 (PST) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga102.jf.intel.com with ESMTP; 27 Dec 2016 17:37:37 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,419,1477983600"; d="scan'208";a="916689622" Received: from fmsmsx105.amr.corp.intel.com ([10.18.124.203]) by orsmga003.jf.intel.com with ESMTP; 27 Dec 2016 17:37:38 -0800 Received: from fmsmsx111.amr.corp.intel.com (10.18.116.5) by FMSMSX105.amr.corp.intel.com (10.18.124.203) with Microsoft SMTP Server (TLS) id 14.3.248.2; Tue, 27 Dec 2016 17:37:38 -0800 Received: from shsmsx103.ccr.corp.intel.com (10.239.4.69) by fmsmsx111.amr.corp.intel.com (10.18.116.5) with Microsoft SMTP Server (TLS) id 14.3.248.2; Tue, 27 Dec 2016 17:37:37 -0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.88]) by SHSMSX103.ccr.corp.intel.com ([10.239.4.69]) with mapi id 14.03.0248.002; Wed, 28 Dec 2016 09:37:35 +0800 From: "Fan, Jeff" To: "Yao, Jiewen" , "edk2-devel@lists.01.org" CC: "Zeng, Star" Thread-Topic: [PATCH 1/2] UefiCpuPkg/MicrocodeUpdate: enhance flash write logic Thread-Index: AQHSYBX1yMGzp5XzrkC2rXEfHG1+MqEclaWg Date: Wed, 28 Dec 2016 01:37:34 +0000 Message-ID: <542CF652F8836A4AB8DBFAAD40ED192A4C506190@shsmsx102.ccr.corp.intel.com> References: <1482825026-3224-1-git-send-email-jiewen.yao@intel.com> <1482825026-3224-2-git-send-email-jiewen.yao@intel.com> In-Reply-To: <1482825026-3224-2-git-send-email-jiewen.yao@intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiYTRmZTJkOTQtZDhhOS00MzA2LWJjNjEtYmJlNDMyN2ZlM2Y1IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE1LjkuNi42IiwiVHJ1c3RlZExhYmVsSGFzaCI6IkI4UGM5TVBtYmdDNW15MlI2Tk13OWpEeWJRTmVHRE1leDJWK2NOUG9RbUE9In0= x-ctpclassification: CTP_IC x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH 1/2] UefiCpuPkg/MicrocodeUpdate: enhance flash write logic X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Dec 2016 01:37:38 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: Jeff Fan -----Original Message----- From: Yao, Jiewen=20 Sent: Tuesday, December 27, 2016 3:50 PM To: edk2-devel@lists.01.org Cc: Fan, Jeff; Zeng, Star Subject: [PATCH 1/2] UefiCpuPkg/MicrocodeUpdate: enhance flash write logic The patch updated MicrocodeWrite() to move the Microcode replacement logic = to a standalone function - UpdateMicrocodeFlashRegion(). More detail description is added in UpdateMicrocodeFlashRegion() to improve= readability. The Microcode information is collected in InitializeMicrocodeDescriptor(), = so that FmpGetImage() can get the info directly. MicrocodeRead() is not needed any more. Cc: Jeff Fan Cc: Star Zeng Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao --- UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c | 40 +- UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c | 684 ++++= ++++++++-------- UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUp= date.h | 84 ++- 3 files changed, 492 insertions(+), 316 deletions(-) diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c b= /UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c index df3563d..97f2f35 100644 --- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c +++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c @@ -174,7 +174,7 @@ FmpGetImage ( ) { MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate; - EFI_STATUS Status; + MICROCODE_INFO *MicrocodeInfo; =20 if (Image =3D=3D NULL || ImageSize =3D=3D NULL) { return EFI_INVALID_PARAMETER; @@ -186,8 +186,16 @@ FmpGetImage ( return EFI_INVALID_PARAMETER; } =20 - Status =3D MicrocodeRead(ImageIndex, (VOID *)Image, ImageSize); - return Status; + MicrocodeInfo =3D &MicrocodeFmpPrivate->MicrocodeInfo[ImageIndex - 1]; + + if (*ImageSize < MicrocodeInfo->TotalSize) { + *ImageSize =3D MicrocodeInfo->TotalSize; + return EFI_BUFFER_TOO_SMALL; + } + + *ImageSize =3D MicrocodeInfo->TotalSize; CopyMem (Image,=20 + MicrocodeInfo->MicrocodeEntryPoint, MicrocodeInfo->TotalSize); return=20 + EFI_SUCCESS; } =20 /** @@ -263,7 +271,7 @@ FmpSetImage ( return EFI_INVALID_PARAMETER; } =20 - Status =3D MicrocodeWrite(ImageIndex, (VOID *)Image, ImageSize, &Microco= deFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAtt= empt.LastAttemptStatus, AbortReason); + Status =3D MicrocodeWrite(MicrocodeFmpPrivate, (VOID *)Image,=20 + ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion,=20 + &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason); DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n= ", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate= ->LastAttempt.LastAttemptStatus)); VarStatus =3D gRT->SetVariable( MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME, @@ -417,17 +425,22 @@ InitializeMicrocodeDescriptor ( IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate ) { - UINT8 CurrentMicrocodeCount; + UINT8 CurrentMicrocodeCount; =20 - CurrentMicrocodeCount =3D (UINT8)GetMicrocodeInfo(NULL, 0); + CurrentMicrocodeCount =3D (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate,= =20 + 0, NULL, NULL); =20 if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) { if (MicrocodeFmpPrivate->ImageDescriptor !=3D NULL) { FreePool(MicrocodeFmpPrivate->ImageDescriptor); MicrocodeFmpPrivate->ImageDescriptor =3D NULL; } + if (MicrocodeFmpPrivate->MicrocodeInfo !=3D NULL) { + FreePool(MicrocodeFmpPrivate->MicrocodeInfo); + MicrocodeFmpPrivate->MicrocodeInfo =3D NULL; + } } else { ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->Des= criptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)); + ZeroMem(MicrocodeFmpPrivate->MicrocodeInfo,=20 + MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO)); } =20 MicrocodeFmpPrivate->DescriptorCount =3D CurrentMicrocodeCount; @@ -438,= 8 +451,14 @@ InitializeMicrocodeDescriptor ( return EFI_OUT_OF_RESOURCES; } } + if (MicrocodeFmpPrivate->MicrocodeInfo =3D=3D NULL) { + MicrocodeFmpPrivate->MicrocodeInfo =3D AllocateZeroPool(MicrocodeFmpPr= ivate->DescriptorCount * sizeof(MICROCODE_INFO)); + if (MicrocodeFmpPrivate->MicrocodeInfo =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + } =20 - CurrentMicrocodeCount =3D (UINT8)GetMicrocodeInfo(MicrocodeFmpPrivate->I= mageDescriptor, MicrocodeFmpPrivate->DescriptorCount); + CurrentMicrocodeCount =3D (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate,= =20 + MicrocodeFmpPrivate->DescriptorCount,=20 + MicrocodeFmpPrivate->ImageDescriptor,=20 + MicrocodeFmpPrivate->MicrocodeInfo); ASSERT(CurrentMicrocodeCount =3D=3D MicrocodeFmpPrivate->DescriptorCount= ); =20 return EFI_SUCCESS; @@ -460,6 +479,7 @@ InitializePrivateData ( EFI_STATUS Status; EFI_STATUS VarStatus; UINTN VarSize; + BOOLEAN Result; =20 MicrocodeFmpPrivate->Signature =3D MICROCODE_FMP_PRIVATE_DATA_SIGN= ATURE; MicrocodeFmpPrivate->Handle =3D NULL; @@ -481,6 +501,12 @@ InitializePrivateData ( DEBUG((DEBUG_INFO, "GetLastAttemp - %r\n", VarStatus)); DEBUG((DEBUG_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", Micro= codeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAt= tempt.LastAttemptStatus)); =20 + Result =3D=20 + GetMicrocodeRegion(&MicrocodeFmpPrivate->MicrocodePatchAddress,=20 + &MicrocodeFmpPrivate->MicrocodePatchRegionSize); + if (!Result) { + DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); + return EFI_NOT_FOUND; + } + Status =3D InitializeMicrocodeDescriptor(MicrocodeFmpPrivate); =20 return Status; diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.= c b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c index 2eb4ae4..46739ba 100644 --- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c +++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c @@ -21,6 +21,36 @@ =20 #include "MicrocodeUpdate.h" =20 + +/** + Verify Microcode. + + Caution: This function may receive untrusted input. + + @param[in] Image The Microcode image buffer. + @param[in] ImageSize The size of Microcode image buffer in byt= es. + @param[in] TryLoad Try to load Microcode or not. + @param[out] LastAttemptStatus The last attempt status, which will be re= corded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] AbortReason A pointer to a pointer to a null-terminat= ed string providing more + details for the aborted operation. The bu= ffer is allocated by this function + with AllocatePool(), and it is the caller= 's responsibility to free it with a + call to FreePool(). + + @retval EFI_SUCCESS The Microcode image passes verificatio= n. + @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt. + @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorre= ct. + @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or Pr= ocessorFlags is incorrect. + @retval EFI_SECURITY_VIOLATION The Microcode image fails to load. +**/ +EFI_STATUS +VerifyMicrocode ( + IN VOID *Image, + IN UINTN ImageSize, + IN BOOLEAN TryLoad, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ); + /** Get Microcode Region. =20 @@ -32,14 +62,14 @@ **/ BOOLEAN GetMicrocodeRegion ( - OUT UINT64 *MicrocodePatchAddress, - OUT UINT64 *MicrocodePatchRegionSize + OUT VOID **MicrocodePatchAddress, + OUT UINTN *MicrocodePatchRegionSize ) { - *MicrocodePatchAddress =3D PcdGet64(PcdCpuMicrocodePatchAddress); - *MicrocodePatchRegionSize =3D PcdGet64(PcdCpuMicrocodePatchRegionSize); + *MicrocodePatchAddress =3D (VOID=20 + *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress); + *MicrocodePatchRegionSize =3D=20 + (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize); =20 - if ((*MicrocodePatchAddress =3D=3D 0) || (*MicrocodePatchRegionSize =3D= =3D 0)) { + if ((*MicrocodePatchAddress =3D=3D NULL) || (*MicrocodePatchRegionSize = =3D=3D=20 + 0)) { return FALSE; } =20 @@ -114,40 +144,79 @@ LoadMicrocode ( } =20 /** + If the Microcode is used by current processor. + + @param[in] MicrocodeEntryPoint The Microcode buffer + + @retval TRUE The Microcode is used by current processor. + @retval FALSE The Microcode is NOT used by current processor. +**/ +BOOLEAN +IsMicrocodeInUse ( + IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint + ) +{ + UINT32 AttemptStatus; + UINTN TotalSize; + EFI_STATUS Status; + + if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoint= ->LoaderRevision =3D=3D 0x1) { + // + // It is the microcode header. It is not the padding data between micr= ocode patches + // becasue the padding data should not include 0x00000001 and it shoul= d be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->DataSize =3D=3D 0) { + TotalSize =3D 2048; + } else { + TotalSize =3D MicrocodeEntryPoint->TotalSize; + } + Status =3D VerifyMicrocode(MicrocodeEntryPoint, TotalSize, FALSE, &Att= emptStatus, NULL); + if (!EFI_ERROR(Status)) { + return TRUE; + } + } + return FALSE; +} + +/** Get current Microcode information. =20 - @param[out] ImageDescriptor Microcode ImageDescriptor - @param[in] DescriptorCount The count of Microcode ImageDescriptor all= ocated. + NOTE: The DescriptorCount/ImageDescriptor/MicrocodeInfo in=20 + MicrocodeFmpPrivate are not avaiable in this function. + + @param[in] MicrocodeFmpPrivate The Microcode driver private dat= a + @param[in] DescriptorCount The count of Microcode ImageDesc= riptor allocated. + @param[out] ImageDescriptor Microcode ImageDescriptor + @param[out] MicrocodeInfo Microcode information =20 @return Microcode count **/ UINTN GetMicrocodeInfo ( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate, + IN UINTN DescriptorCount, OPTIONAL OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL - IN UINTN DescriptorCount OPTIONAL + OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL ) { - BOOLEAN Result; - UINT64 MicrocodePatchAddress; - UINT64 MicrocodePatchRegionSize; + VOID *MicrocodePatchAddress; + UINTN MicrocodePatchRegionSize; CPU_MICROCODE_HEADER *MicrocodeEntryPoint; UINTN MicrocodeEnd; UINTN TotalSize; UINTN Count; UINT64 ImageAttributes; - UINT32 CurrentRevision; + BOOLEAN IsInUse; =20 - Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); - if (!Result) { - DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); - return 0; - } - DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchA= ddress, MicrocodePatchRegionSize)); + MicrocodePatchAddress =3D MicrocodeFmpPrivate->MicrocodePatchAddress; + MicrocodePatchRegionSize =3D=20 + MicrocodeFmpPrivate->MicrocodePatchRegionSize; + + DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n",=20 + MicrocodePatchAddress, MicrocodePatchRegionSize)); =20 Count =3D 0; - CurrentRevision =3D GetCurrentMicrocodeSignature(); =20 - MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); + MicrocodeEnd =3D (UINTN)MicrocodePatchAddress +=20 + MicrocodePatchRegionSize; MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchA= ddress; do { if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { @@ -162,6 +231,8 @@ GetMicrocodeInfo ( TotalSize =3D MicrocodeEntryPoint->TotalSize; } =20 + IsInUse =3D IsMicrocodeInUse (MicrocodeEntryPoint); + if (ImageDescriptor !=3D NULL && DescriptorCount > Count) { ImageDescriptor[Count].ImageIndex =3D (UINT8)(Count + 1); CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImage= TypeIdGuid); @@ -171,7 +242,7 @@ GetMicrocodeInfo ( ImageDescriptor[Count].VersionName =3D NULL; ImageDescriptor[Count].Size =3D TotalSize; ImageAttributes =3D IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIB= UTE_RESET_REQUIRED; - if (CurrentRevision =3D=3D MicrocodeEntryPoint->UpdateRevision) { + if (IsInUse) { ImageAttributes |=3D IMAGE_ATTRIBUTE_IN_USE; } ImageDescriptor[Count].AttributesSupported =3D ImageAttributes | I= MAGE_ATTRIBUTE_IN_USE; @@ -182,6 +253,11 @@ GetMicrocodeInfo ( ImageDescriptor[Count].LastAttemptStatus =3D 0; ImageDescriptor[Count].HardwareInstance =3D 0; } + if (MicrocodeInfo !=3D NULL && DescriptorCount > Count) { + MicrocodeInfo[Count].MicrocodeEntryPoint =3D MicrocodeEntryPoint; + MicrocodeInfo[Count].TotalSize =3D TotalSize; + MicrocodeInfo[Count].InUse =3D IsInUse; + } } else { // // It is the padding data between the microcode patches for microcod= e patches alignment. @@ -207,89 +283,6 @@ GetMicrocodeInfo ( } =20 /** - Read Microcode. - - @param[in] ImageIndex The index of Microcode image. - @param[in, out] Image The Microcode image buffer. - @param[in, out] ImageSize The size of Microcode image buffer in bytes. - - @retval EFI_SUCCESS The Microcode image is read. - @retval EFI_NOT_FOUND The Microcode image is not found. -**/ -EFI_STATUS -MicrocodeRead ( - IN UINTN ImageIndex, - IN OUT VOID *Image, - IN OUT UINTN *ImageSize - ) -{ - BOOLEAN Result; - UINT64 MicrocodePatchAddress; - UINT64 MicrocodePatchRegionSize; - CPU_MICROCODE_HEADER *MicrocodeEntryPoint; - UINTN MicrocodeEnd; - UINTN TotalSize; - UINTN Count; - - Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); - if (!Result) { - DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); - return EFI_NOT_FOUND; - } - DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchA= ddress, MicrocodePatchRegionSize)); - - Count =3D 0; - - MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAdd= ress; - do { - if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { - // - // It is the microcode header. It is not the padding data between mi= crocode patches - // becasue the padding data should not include 0x00000001 and it sho= uld be the repeated - // byte format (like 0xXYXYXYXY....). - // - if (MicrocodeEntryPoint->DataSize =3D=3D 0) { - TotalSize =3D 2048; - } else { - TotalSize =3D MicrocodeEntryPoint->TotalSize; - } - - if (ImageIndex =3D=3D Count + 1) { - if (*ImageSize < TotalSize) { - *ImageSize =3D TotalSize; - return EFI_BUFFER_TOO_SMALL; - } - *ImageSize =3D TotalSize; - CopyMem (Image, MicrocodeEntryPoint, TotalSize); - return EFI_SUCCESS; - } - - } else { - // - // It is the padding data between the microcode patches for microcod= e patches alignment. - // Because the microcode patch is the multiple of 1-KByte, the paddi= ng data should not - // exist if the microcode patch alignment value is not larger than 1= -KByte. So, the microcode - // alignment value should be larger than 1-KByte. We could skip SIZE= _1KB padding data to - // find the next possible microcode patch header. - // - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEn= tryPoint) + SIZE_1KB); - continue; - } - - Count++; - ASSERT(Count < 0xFF); - - // - // Get the next patch. - // - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntr= yPoint) + TotalSize); - } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); - - return EFI_NOT_FOUND; -} - -/** Verify Microcode. =20 Caution: This function may receive untrusted input. @@ -461,7 +454,9 @@ VerifyMicrocode ( } } if (!CorrectMicrocode) { - DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSigna= ture/ProcessorFlags\n")); + if (TryLoad) { + DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSig= nature/ProcessorFlags\n")); + } *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; if (AbortReason !=3D NULL) { if (MicrocodeEntryPoint->ProcessorSignature.Uint32 !=3D CurrentPro= cessorSignature) { @@ -479,7 +474,9 @@ VerifyMicrocode ( // CurrentRevision =3D GetCurrentMicrocodeSignature(); if (MicrocodeEntryPoint->UpdateRevision < CurrentRevision) { - DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n")); + if (TryLoad) { + DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n")); + } *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; if (AbortReason !=3D NULL) { *AbortReason =3D AllocateCopyPool(sizeof(L"IncorrectRevision"), L"In= correctRevision"); @@ -508,142 +505,79 @@ VerifyMicrocode ( /** Get current Microcode in used. =20 + @param[in] MicrocodeFmpPrivate The Microcode driver private data + @return current Microcode in used. **/ VOID * GetCurrentMicrocodeInUse ( - VOID + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate ) { - BOOLEAN Result; - EFI_STATUS Status; - UINT64 MicrocodePatchAddress; - UINT64 MicrocodePatchRegionSize; - CPU_MICROCODE_HEADER *MicrocodeEntryPoint; - UINTN MicrocodeEnd; - UINTN TotalSize; - UINTN Count; - UINT32 AttemptStatus; + UINTN Index; =20 - Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); - if (!Result) { - DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); - return NULL; + for (Index =3D 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++)= { + if (!MicrocodeFmpPrivate->MicrocodeInfo[Index].InUse) { + continue; + } + if (IsMicrocodeInUse (MicrocodeFmpPrivate->MicrocodeInfo[Index].Microc= odeEntryPoint)) { + return MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint= ; + } } - DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchA= ddress, MicrocodePatchRegionSize)); + return NULL; +} =20 - Count =3D 0; +/** + Get next Microcode entrypoint. =20 - MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAdd= ress; - do { - if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { - // - // It is the microcode header. It is not the padding data between mi= crocode patches - // becasue the padding data should not include 0x00000001 and it sho= uld be the repeated - // byte format (like 0xXYXYXYXY....). - // - if (MicrocodeEntryPoint->DataSize =3D=3D 0) { - TotalSize =3D 2048; + @param[in] MicrocodeFmpPrivate The Microcode driver private data + @param[in] MicrocodeEntryPoint Current Microcode entrypoint + + @return next Microcode entrypoint. +**/ +CPU_MICROCODE_HEADER * +GetNextMicrocode ( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate, + IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint + ) +{ + UINTN Index; + + for (Index =3D 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++)= { + if (MicrocodeEntryPoint =3D=3D MicrocodeFmpPrivate->MicrocodeInfo[Inde= x].MicrocodeEntryPoint) { + if (Index =3D=3D (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) { + // it is last one + return NULL; } else { - TotalSize =3D MicrocodeEntryPoint->TotalSize; + // return next one + return MicrocodeFmpPrivate->MicrocodeInfo[Index +=20 + 1].MicrocodeEntryPoint; } - Status =3D VerifyMicrocode(MicrocodeEntryPoint, TotalSize, FALSE, &A= ttemptStatus, NULL); - if (!EFI_ERROR(Status)) { - return MicrocodeEntryPoint; - } - - } else { - // - // It is the padding data between the microcode patches for microcod= e patches alignment. - // Because the microcode patch is the multiple of 1-KByte, the paddi= ng data should not - // exist if the microcode patch alignment value is not larger than 1= -KByte. So, the microcode - // alignment value should be larger than 1-KByte. We could skip SIZE= _1KB padding data to - // find the next possible microcode patch header. - // - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEn= tryPoint) + SIZE_1KB); - continue; } + } =20 - Count++; - ASSERT(Count < 0xFF); - - // - // Get the next patch. - // - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntr= yPoint) + TotalSize); - } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); - + ASSERT(FALSE); return NULL; } =20 /** Get current Microcode used region size. =20 + @param[in] MicrocodeFmpPrivate The Microcode driver private data + @return current Microcode used region size. **/ UINTN GetCurrentMicrocodeUsedRegionSize ( - VOID + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate ) { - BOOLEAN Result; - UINT64 MicrocodePatchAddress; - UINT64 MicrocodePatchRegionSize; - CPU_MICROCODE_HEADER *MicrocodeEntryPoint; - UINTN MicrocodeEnd; - UINTN TotalSize; - UINTN Count; - UINTN MicrocodeUsedEnd; - - Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); - if (!Result) { - DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); + if (MicrocodeFmpPrivate->DescriptorCount =3D=3D 0) { return 0; } - DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchA= ddress, MicrocodePatchRegionSize)); - - MicrocodeUsedEnd =3D (UINTN)MicrocodePatchAddress; - Count =3D 0; - - MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAdd= ress; - do { - if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { - // - // It is the microcode header. It is not the padding data between mi= crocode patches - // becasue the padding data should not include 0x00000001 and it sho= uld be the repeated - // byte format (like 0xXYXYXYXY....). - // - if (MicrocodeEntryPoint->DataSize =3D=3D 0) { - TotalSize =3D 2048; - } else { - TotalSize =3D MicrocodeEntryPoint->TotalSize; - } - - } else { - // - // It is the padding data between the microcode patches for microcod= e patches alignment. - // Because the microcode patch is the multiple of 1-KByte, the paddi= ng data should not - // exist if the microcode patch alignment value is not larger than 1= -KByte. So, the microcode - // alignment value should be larger than 1-KByte. We could skip SIZE= _1KB padding data to - // find the next possible microcode patch header. - // - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEn= tryPoint) + SIZE_1KB); - continue; - } - - Count++; - ASSERT(Count < 0xFF); - MicrocodeUsedEnd =3D (UINTN)MicrocodeEntryPoint; =20 - // - // Get the next patch. - // - MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntr= yPoint) + TotalSize); - } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); - - return MicrocodeUsedEnd - (UINTN)MicrocodePatchAddress; + return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->De= scriptorCount - 1].MicrocodeEntryPoint + + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->= DescriptorCount - 1].TotalSize + - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress; } =20 /** @@ -685,62 +619,283 @@ UpdateMicrocode ( } =20 /** - Write Microcode. + Update Microcode flash region. =20 - Caution: This function may receive untrusted input. - - @param[in] ImageIndex The index of Microcode image. - @param[in] Image The Microcode image buffer. - @param[in] ImageSize The size of Microcode image buffer in by= tes. - @param[out] LastAttemptVersion The last attempt version, which will be = recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. - @param[out] LastAttemptStatus The last attempt status, which will be r= ecorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. - @param[out] AbortReason A pointer to a pointer to a null-termina= ted string providing more - details for the aborted operation. The buffer= is allocated by this function - with AllocatePool(), and it is the caller's r= esponsibility to free it with a - call to FreePool(). + @param[in] MicrocodeFmpPrivate The Microcode driver private data + @param[in] CurrentMicrocodeEntryPoint Current Microcode entrypoint + @param[in] Image The Microcode image buffer. + @param[in] ImageSize The size of Microcode image buffe= r in bytes. + @param[out] LastAttemptStatus The last attempt status, which wi= ll be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. =20 - @retval EFI_SUCCESS The Microcode image is written. - @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt. - @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorre= ct. - @retval EFI_SECURITY_VIOLATION The Microcode image fails to load. - @retval EFI_WRITE_PROTECTED The flash device is read only. + @retval EFI_SUCCESS The Microcode image is written. + @retval EFI_WRITE_PROTECTED The flash device is read only. **/ EFI_STATUS -MicrocodeWrite ( - IN UINTN ImageIndex, - IN VOID *Image, - IN UINTN ImageSize, - OUT UINT32 *LastAttemptVersion, - OUT UINT32 *LastAttemptStatus, - OUT CHAR16 **AbortReason +UpdateMicrocodeFlashRegion ( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate, + IN CPU_MICROCODE_HEADER *CurrentMicrocodeEntryPoint, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptStatus ) { - BOOLEAN Result; - EFI_STATUS Status; - UINT64 MicrocodePatchAddress; - UINT64 MicrocodePatchRegionSize; - CPU_MICROCODE_HEADER *CurrentMicrocodeEntryPoint; + VOID *MicrocodePatchAddress; + UINTN MicrocodePatchRegionSize; UINTN CurrentTotalSize; UINTN UsedRegionSize; - VOID *AlignedImage; + EFI_STATUS Status; + VOID *MicrocodePatchScratchBuffer; + UINT8 *ScratchBufferPtr; + UINTN ScratchBufferSize; + UINTN RestSize; + UINTN AvailableSize; + VOID *NextMicrocodeEntryPoint; + MICROCODE_INFO *MicrocodeInfo; + UINTN MicrocodeCount; + UINTN Index; + + DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size -=20 + 0x%x\n", Image, ImageSize)); =20 - Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); - if (!Result) { - DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); - return EFI_NOT_FOUND; + MicrocodePatchAddress =3D MicrocodeFmpPrivate->MicrocodePatchAddress; + MicrocodePatchRegionSize =3D=20 + MicrocodeFmpPrivate->MicrocodePatchRegionSize; + + MicrocodePatchScratchBuffer =3D AllocateZeroPool=20 + (MicrocodePatchRegionSize); if (MicrocodePatchScratchBuffer =3D=3D NULL)= { + DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCE= S; + return EFI_OUT_OF_RESOURCES; } + ScratchBufferPtr =3D MicrocodePatchScratchBuffer; ScratchBufferSize =3D= =20 + 0; =20 + // + // Current data collection + // CurrentTotalSize =3D 0; - CurrentMicrocodeEntryPoint =3D GetCurrentMicrocodeInUse(); + AvailableSize =3D 0; + NextMicrocodeEntryPoint =3D NULL; if (CurrentMicrocodeEntryPoint !=3D NULL) { if (CurrentMicrocodeEntryPoint->DataSize =3D=3D 0) { CurrentTotalSize =3D 2048; } else { CurrentTotalSize =3D CurrentMicrocodeEntryPoint->TotalSize; } + DEBUG((DEBUG_INFO, " CurrentTotalSize - 0x%x\n", CurrentTotalSize)); + NextMicrocodeEntryPoint =3D GetNextMicrocode(MicrocodeFmpPrivate, Curr= entMicrocodeEntryPoint); + DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocode= EntryPoint)); + if (NextMicrocodeEntryPoint !=3D NULL) { + ASSERT ((UINTN)NextMicrocodeEntryPoint >=3D ((UINTN)CurrentMicrocode= EntryPoint + CurrentTotalSize)); + AvailableSize =3D (UINTN)NextMicrocodeEntryPoint - (UINTN)CurrentMic= rocodeEntryPoint; + } else { + AvailableSize =3D (UINTN)MicrocodePatchAddress + MicrocodePatchRegio= nSize - (UINTN)CurrentMicrocodeEntryPoint; + } + DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize)); } =20 + ASSERT (AvailableSize >=3D CurrentTotalSize); UsedRegionSize =3D=20 + GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate); + DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize)); =20 + ASSERT (UsedRegionSize >=3D CurrentTotalSize); if=20 + (CurrentMicrocodeEntryPoint !=3D NULL) { + ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >=3D=20 + ((UINTN)CurrentMicrocodeEntryPoint + CurrentTotalSize)); } // //=20 + Total Size means the Microcode data size. + // Available Size means the Microcode data size plus the pad till next (= 1) Microcode or (2) the end. + // + // (1) + // +------+-----------+-----+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D+ + // | MCU1 | Microcode | PAD | MCU2 | Empty | + // +------+-----------+-----+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D+ + // | TotalSize | + // |<-AvailableSize->| + // |<- UsedRegionSize ->| + // + // (2) + // +------+-----------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D+ + // | MCU | Microcode | Empty | + // +------+-----------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D+ + // | TotalSize | + // |<- AvailableSize ->| + // |<-UsedRegionSize->| + // + + // + // Update based on policy + // + + // + // 1. If there is enough space to update old one in situ, replace old mi= crocode in situ. + // + if (AvailableSize >=3D ImageSize) { + DEBUG((DEBUG_INFO, "Replace old microcode in situ\n")); + // + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + // |Other1| Old Image |Other2| Empty | + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + // + // +------+---------+--+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + // |Other1|New Image|FF|Other2| Empty | + // +------+---------+--+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + // + // 1.1. Copy new image + CopyMem (ScratchBufferPtr, Image, ImageSize); + ScratchBufferSize +=3D ImageSize; + ScratchBufferPtr =3D (UINT8 *)ScratchBufferPtr + ScratchBufferSize; + // 1.2. Pad 0xFF + RestSize =3D AvailableSize - ImageSize; + if (RestSize > 0) { + SetMem (ScratchBufferPtr, RestSize, 0xFF); + ScratchBufferSize +=3D RestSize; + ScratchBufferPtr =3D (UINT8 *)ScratchBufferPtr + ScratchBufferSize; + } + Status =3D UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, Microcod= ePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus); + return Status; } =20 // + // 2. If there is enough space to remove old one and add new one, reorg = and replace old microcode. + // + if (MicrocodePatchRegionSize - (UsedRegionSize - CurrentTotalSize) >=3D = ImageSize) { + if (CurrentMicrocodeEntryPoint =3D=3D NULL) { + DEBUG((DEBUG_INFO, "Append new microcode\n")); + // + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D+ + // |Other1| Other |Other2| Empty | + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D+ + // + // +------+------------+------+-----------+=3D=3D=3D=3D=3D=3D=3D+ + // |Other1| Other |Other2| New Image | Empty | + // +------+------------+------+-----------+=3D=3D=3D=3D=3D=3D=3D+ + // + Status =3D UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegion= Size, Image, ImageSize, LastAttemptStatus); + } else { + DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n")); + // + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D+ + // |Other1| Old Image |Other2| Empty | + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D+ + // + // +------+---------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D+ + // |Other1| New Image |Other2| Empty | + // +------+---------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D+ + // + // 2.1. Copy new image + CopyMem (MicrocodePatchScratchBuffer, Image, ImageSize); + ScratchBufferSize +=3D ImageSize; + ScratchBufferPtr =3D (UINT8 *)ScratchBufferPtr + ScratchBufferSize; + // 2.2. Copy rest images after the old image. + if (NextMicrocodeEntryPoint !=3D 0) { + RestSize =3D (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UIN= TN)NextMicrocodeEntryPoint); + CopyMem (ScratchBufferPtr, (UINT8 *)CurrentMicrocodeEntryPoint + C= urrentTotalSize, RestSize); + ScratchBufferSize +=3D RestSize; + ScratchBufferPtr =3D (UINT8 *)ScratchBufferPtr + ScratchBufferSize= ; + } + Status =3D UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, Microc= odePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus); + } + return Status; + } + + // + // 3. The new image can be put in MCU region, but not all others can be = put. + // So all the unused MCU is removed. + // + if (MicrocodePatchRegionSize >=3D ImageSize) { + // + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + // |Other1| Old Image |Other2| Empty | + // +------+------------+------+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D+ + // + // +-------------------------------------+--------+ + // | New Image | Other | + // +-------------------------------------+--------+ + // + DEBUG((DEBUG_INFO, "Add new microcode from beginning\n")); + + MicrocodeCount =3D MicrocodeFmpPrivate->DescriptorCount; + MicrocodeInfo =3D MicrocodeFmpPrivate->MicrocodeInfo; + + // 3.1. Copy new image + CopyMem (MicrocodePatchScratchBuffer, Image, ImageSize); + ScratchBufferSize +=3D ImageSize; + ScratchBufferPtr =3D (UINT8 *)ScratchBufferPtr + ScratchBufferSize; + // 3.2. Copy some others to rest buffer + for (Index =3D 0; Index < MicrocodeCount; Index++) { + if (!MicrocodeInfo[Index].InUse) { + continue; + } + if (MicrocodeInfo[Index].MicrocodeEntryPoint =3D=3D CurrentMicrocode= EntryPoint) { + continue; + } + if (MicrocodeInfo[Index].TotalSize <=3D MicrocodePatchRegionSize - S= cratchBufferSize) { + CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoin= t, MicrocodeInfo[Index].TotalSize); + ScratchBufferSize +=3D MicrocodeInfo[Index].TotalSize; + ScratchBufferPtr =3D (UINT8 *)ScratchBufferPtr + ScratchBufferSize= ; + } + } + // 3.3. Pad 0xFF + RestSize =3D MicrocodePatchRegionSize - ScratchBufferSize; + if (RestSize > 0) { + SetMem (ScratchBufferPtr, RestSize, 0xFF); + ScratchBufferSize +=3D RestSize; + ScratchBufferPtr =3D (UINT8 *)ScratchBufferPtr + ScratchBufferSize; + } + Status =3D UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatc= hScratchBuffer, ScratchBufferSize, LastAttemptStatus); + return Status; + } + + // + // 4. The new image size is bigger than the whole MCU region. + // + DEBUG((DEBUG_ERROR, "Microcode too big\n")); *LastAttemptStatus =3D=20 + LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; + Status =3D EFI_OUT_OF_RESOURCES; + + return Status; +} + +/** + Write Microcode. + + Caution: This function may receive untrusted input. + + @param[in] MicrocodeFmpPrivate The Microcode driver private data + @param[in] Image The Microcode image buffer. + @param[in] ImageSize The size of Microcode image buffer in b= ytes. + @param[out] LastAttemptVersion The last attempt version, which will be= recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] LastAttemptStatus The last attempt status, which will be = recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] AbortReason A pointer to a pointer to a null-termin= ated string providing more + details for the aborted operation. The = buffer is allocated by this function + with AllocatePool(), and it is the call= er's responsibility to free it with a + call to FreePool(). + + @retval EFI_SUCCESS The Microcode image is written. + @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt. + @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorre= ct. + @retval EFI_SECURITY_VIOLATION The Microcode image fails to load. + @retval EFI_WRITE_PROTECTED The flash device is read only. +**/ +EFI_STATUS +MicrocodeWrite ( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ) +{ + EFI_STATUS Status; + VOID *AlignedImage; + CPU_MICROCODE_HEADER *CurrentMicrocodeEntryPoint; + + // + // We must get Current MicrocodeEntrypoint *before* VerifyMicrocode, =20 + // because the MicrocodeSignature might be updated in VerifyMicrocode. + // + CurrentMicrocodeEntryPoint =3D=20 + GetCurrentMicrocodeInUse(MicrocodeFmpPrivate); + DEBUG((DEBUG_INFO, " CurrentMicrocodeEntryPoint - 0x%x\n",=20 + CurrentMicrocodeEntryPoint)); + + // // MCU must be 16 bytes aligned // AlignedImage =3D AllocateCopyPool(ImageSize, Image); @@ -759,32 +914,13 = @@ MicrocodeWrite ( } DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n")); =20 - if (CurrentTotalSize < ImageSize) { - UsedRegionSize =3D GetCurrentMicrocodeUsedRegionSize(); - if (MicrocodePatchRegionSize - UsedRegionSize >=3D ImageSize) { - // - // Append - // - DEBUG((DEBUG_INFO, "Append new microcode\n")); - Status =3D UpdateMicrocode(MicrocodePatchAddress + UsedRegionSize, A= lignedImage, ImageSize, LastAttemptStatus); - } else if (MicrocodePatchRegionSize >=3D ImageSize) { - // - // Ignor all others and just add this one from beginning. - // - DEBUG((DEBUG_INFO, "Add new microcode from beginning\n")); - Status =3D UpdateMicrocode(MicrocodePatchAddress, AlignedImage, Imag= eSize, LastAttemptStatus); - } else { - DEBUG((DEBUG_ERROR, "Microcode too big\n")); - *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOUR= CES; - Status =3D EFI_OUT_OF_RESOURCES; - } - } else { - // - // Replace - // - DEBUG((DEBUG_INFO, "Replace old microcode\n")); - Status =3D UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, AlignedI= mage, ImageSize, LastAttemptStatus); - } + Status =3D UpdateMicrocodeFlashRegion( + MicrocodeFmpPrivate, + CurrentMicrocodeEntryPoint, + AlignedImage, + ImageSize, + LastAttemptStatus + ); =20 FreePool(AlignedImage); =20 diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.= h b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h index 77e8441..b4d1bac 100644 --- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h +++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h @@ -50,12 +50,21 @@ typedef struct { UINT32 LastAttemptStatus; } MICROCODE_FMP_LAST_ATTEMPT_VARIABLE; =20 +typedef struct { + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN TotalSize; + BOOLEAN InUse; +} MICROCODE_INFO; + struct _MICROCODE_FMP_PRIVATE_DATA { UINT32 Signature; EFI_FIRMWARE_MANAGEMENT_PROTOCOL Fmp; EFI_HANDLE Handle; + VOID *MicrocodePatchAddress; + UINTN MicrocodePatchRegionSize; UINT8 DescriptorCount; EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor; + MICROCODE_INFO *MicrocodeInfo; UINT32 PackageVersion; CHAR16 *PackageVersionName; MICROCODE_FMP_LAST_ATTEMPT_VARIABLE LastAttempt; @@ -84,63 +93,68 @@ ty= pedef struct _MICROCODE_FMP_PRIVATE_DATA MICROCODE_FMP_PRIVATE_DATA; ) =20 /** - Get current Microcode information. + Get Microcode Region. =20 - @param[out] ImageDescriptor Microcode ImageDescriptor - @param[in] DescriptorCount The count of Microcode ImageDescriptor all= ocated. + @param[out] MicrocodePatchAddress The address of Microcode + @param[out] MicrocodePatchRegionSize The region size of Microcode =20 - @return Microcode count + @retval TRUE The Microcode region is returned. + @retval FALSE No Microcode region. **/ -UINTN -GetMicrocodeInfo ( - OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL - IN UINTN DescriptorCount OPTIONAL +BOOLEAN +GetMicrocodeRegion ( + OUT VOID **MicrocodePatchAddress, + OUT UINTN *MicrocodePatchRegionSize ); =20 /** - Read Microcode. + Get current Microcode information. + + NOTE: The DescriptorCount/ImageDescriptor/MicrocodeInfo in=20 + MicrocodeFmpPrivate are not avaiable in this function. =20 - @param[in] ImageIndex The index of Microcode image. - @param[in, out] Image The Microcode image buffer. - @param[in, out] ImageSize The size of Microcode image buffer in bytes. + @param[in] MicrocodeFmpPrivate The Microcode driver private dat= a + @param[in] DescriptorCount The count of Microcode ImageDesc= riptor allocated. + @param[out] ImageDescriptor Microcode ImageDescriptor + @param[out] MicrocodeInfo Microcode information =20 - @retval EFI_SUCCESS The Microcode image is read. - @retval EFI_NOT_FOUND The Microcode image is not found. + @return Microcode count **/ -EFI_STATUS -MicrocodeRead ( - IN UINTN ImageIndex, - IN OUT VOID *Image, - IN OUT UINTN *ImageSize +UINTN +GetMicrocodeInfo ( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate, + IN UINTN DescriptorCount, OPTIONAL + OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL + OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL ); =20 /** Write Microcode. =20 - @param[in] ImageIndex The index of Microcode image. - @param[in] Image The Microcode image buffer. - @param[in] ImageSize The size of Microcode image buffer in by= tes. - @param[out] LastAttemptVersion The last attempt version, which will be = recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. - @param[out] LastAttemptStatus The last attempt status, which will be r= ecorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. - @param[out] AbortReason A pointer to a pointer to a null-termina= ted string providing more - details for the aborted operation. The b= uffer is allocated by this function - with AllocatePool(), and it is the calle= r's responsibility to free it with a - call to FreePool(). + @param[in] MicrocodeFmpPrivate The Microcode driver private data + @param[in] Image The Microcode image buffer. + @param[in] ImageSize The size of Microcode image buffer in b= ytes. + @param[out] LastAttemptVersion The last attempt version, which will be= recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] LastAttemptStatus The last attempt status, which will be = recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] AbortReason A pointer to a pointer to a null-termin= ated string providing more + details for the aborted operation. The = buffer is allocated by this function + with AllocatePool(), and it is the call= er's responsibility to free it with a + call to FreePool(). =20 @retval EFI_SUCCESS The Microcode image is written. @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt. @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorre= ct. @retval EFI_SECURITY_VIOLATION The Microcode image fails to load. - @retval EFI_WRITE_PROTECTED The flash device is read only. + @retval EFI_WRITE_PROTECTED The flash device is read only. **/ EFI_STATUS MicrocodeWrite ( - IN UINTN ImageIndex, - IN VOID *Image, - IN UINTN ImageSize, - OUT UINT32 *LastAttemptVersion, - OUT UINT32 *LastAttemptStatus, - OUT CHAR16 **AbortReason + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason ); =20 /** -- 2.7.4.windows.1