Date
1 - 3 of 3
[PATCH 1/4] UefiCpuPkg: Add MicrocodeLib for loading microcode
Ni, Ray
Signed-off-by: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> --- UefiCpuPkg/Include/Library/MicrocodeLib.h | 120 +++++++ .../Library/MicrocodeLib/MicrocodeLib.c | 322 ++++++++++++++++++ .../Library/MicrocodeLib/MicrocodeLib.inf | 32 ++ UefiCpuPkg/UefiCpuPkg.dec | 5 +- UefiCpuPkg/UefiCpuPkg.dsc | 1 + 5 files changed, 479 insertions(+), 1 deletion(-) create mode 100644 UefiCpuPkg/Include/Library/MicrocodeLib.h create mode 100644 UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c create mode 100644 UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf diff --git a/UefiCpuPkg/Include/Library/MicrocodeLib.h b/UefiCpuPkg/Include= /Library/MicrocodeLib.h new file mode 100644 index 0000000000..2570c43cce --- /dev/null +++ b/UefiCpuPkg/Include/Library/MicrocodeLib.h @@ -0,0 +1,120 @@ +/** @file=0D + Public include file for Microcode library.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef __MICROCODE_LIB_H__=0D +#define __MICROCODE_LIB_H__=0D +=0D +#include <Register/Intel/Microcode.h>=0D +#include <Ppi/ShadowMicrocode.h>=0D +=0D +/**=0D + Get microcode update signature of currently loaded microcode update.=0D +=0D + @return Microcode signature.=0D +**/=0D +UINT32=0D +EFIAPI=0D +GetProcessorMicrocodeSignature (=0D + VOID=0D + );=0D +=0D +/**=0D + Get the processor signature and platform ID for current processor.=0D +=0D + @param MicrocodeCpuId Return the processor signature and platform ID.=0D +**/=0D +VOID=0D +EFIAPI=0D +GetProcessorMicrocodeCpuId (=0D + EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId=0D + );=0D +=0D +/**=0D + Return the total size of the microcode entry.=0D +=0D + Logic follows pseudo code in SDM as below:=0D +=0D + N =3D 512=0D + If (Update.DataSize !=3D 00000000H)=0D + N =3D Update.TotalSize / 4=0D +=0D + If Microcode is NULL, then ASSERT.=0D +=0D + @param Microcode Pointer to the microcode entry.=0D +=0D + @return The microcode total size.=0D +**/=0D +UINT32=0D +EFIAPI=0D +GetMicrocodeLength (=0D + IN CPU_MICROCODE_HEADER *Microcode=0D + );=0D +=0D +/**=0D + Load the microcode to the processor.=0D +=0D + If Microcode is NULL, then ASSERT.=0D +=0D + @param Microcode Pointer to the microcode entry.=0D +**/=0D +VOID=0D +EFIAPI=0D +LoadMicrocode (=0D + IN CPU_MICROCODE_HEADER *Microcode=0D + );=0D +=0D +/**=0D + Detect whether specified processor can find matching microcode patch and= load it.=0D +=0D + Microcode format is as below:=0D + +----------------------------------------+------------------------------= -------------------+=0D + | CPU_MICROCODE_HEADER | = |=0D + +----------------------------------------+ = V=0D + | Update Data | = CPU_MICROCODE_HEADER.Checksum=0D + +----------------------------------------+-------+ = ^=0D + | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | = |=0D + +----------------------------------------+ V = |=0D + | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE= _HEADER.Checksum |=0D + | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ = |=0D + | ... | | = |=0D + +----------------------------------------+-------+----------------------= -------------------+=0D +=0D + There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.=0D + The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignat= ureCount=0D + of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.=0D +=0D + If Microcode is NULL, then ASSERT.=0D +=0D + @param Microcode Pointer to a microcode entry.=0D + @param MicrocodeLength The total length of the microcode entry.=0D + @param MinimumRevision The microcode whose revision <=3D MinimumRev= ision is treated as invalid.=0D + Caller can supply value get from GetProcesso= rMicrocodeSignature() to check=0D + whether the microcode is newer than loaded o= ne.=0D + Caller can supply 0 to treat any revision (e= xcept 0) microcode as valid.=0D + @param MicrocodeCpuIds Pointer to an array of processor signature a= nd platform ID that represents=0D + a set of processors.=0D + Caller can supply zero-element array to skip= the processor signature and=0D + platform ID check.=0D + @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.=0D + @param VerifyChecksum FALSE to skip all the checksum verifications= .=0D +=0D + @retval TRUE The microcode is valid.=0D + @retval FALSE The microcode is invalid.=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsValidMicrocode (=0D + IN CPU_MICROCODE_HEADER *Microcode,=0D + IN UINTN MicrocodeLength,=0D + IN UINT32 MinimumRevision,=0D + IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,=0D + IN UINTN MicrocodeCpuIdCount,=0D + IN BOOLEAN VerifyChecksum=0D + );=0D +=0D +#endif \ No newline at end of file diff --git a/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c b/UefiCpuPkg/Li= brary/MicrocodeLib/MicrocodeLib.c new file mode 100644 index 0000000000..03a43fdae7 --- /dev/null +++ b/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c @@ -0,0 +1,322 @@ +/** @file=0D + Implementation of MicrocodeLib.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include <Uefi/UefiBaseType.h>=0D +#include <Register/Intel/Cpuid.h>=0D +#include <Register/Intel/ArchitecturalMsr.h>=0D +#include <Register/Intel/Microcode.h>=0D +#include <Library/BaseLib.h>=0D +#include <Library/DebugLib.h>=0D +#include <Ppi/ShadowMicrocode.h>=0D +=0D +/**=0D + Get microcode update signature of currently loaded microcode update.=0D +=0D + @return Microcode signature.=0D +**/=0D +UINT32=0D +EFIAPI=0D +GetProcessorMicrocodeSignature (=0D + VOID=0D + )=0D +{=0D + MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;=0D +=0D + AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);=0D + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);=0D + BiosSignIdMsr.Uint64 =3D AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);=0D + return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;=0D +}=0D +=0D +/**=0D + Get the processor signature and platform ID for current processor.=0D +=0D + @param MicrocodeCpuId Return the processor signature and platform ID.=0D +**/=0D +VOID=0D +EFIAPI=0D +GetProcessorMicrocodeCpuId (=0D + EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId=0D + )=0D +{=0D + MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;=0D +=0D + ASSERT (MicrocodeCpuId !=3D NULL);=0D +=0D + PlatformIdMsr.Uint64 =3D AsmReadMsr64 (MSR_IA32_PLATFORM_ID);=0D + MicrocodeCpuId->PlatformId =3D (UINT8) PlatformIdMsr.Bits.PlatformId;=0D + AsmCpuid (CPUID_VERSION_INFO, &MicrocodeCpuId->ProcessorSignature, NULL,= NULL, NULL);=0D +}=0D +=0D +/**=0D + Return the total size of the microcode entry.=0D +=0D + Logic follows pseudo code in SDM as below:=0D +=0D + N =3D 512=0D + If (Update.DataSize !=3D 00000000H)=0D + N =3D Update.TotalSize / 4=0D +=0D + If Microcode is NULL, then ASSERT.=0D +=0D + @param Microcode Pointer to the microcode entry.=0D +=0D + @return The microcode total size.=0D +**/=0D +UINT32=0D +EFIAPI=0D +GetMicrocodeLength (=0D + IN CPU_MICROCODE_HEADER *Microcode=0D + )=0D +{=0D + UINT32 TotalSize;=0D +=0D + ASSERT (Microcode !=3D NULL);=0D +=0D + TotalSize =3D 2048;=0D + if (Microcode->DataSize !=3D 0) {=0D + TotalSize =3D Microcode->TotalSize;=0D + }=0D + return TotalSize;=0D +}=0D +=0D +/**=0D + Load the microcode to the processor.=0D +=0D + If Microcode is NULL, then ASSERT.=0D +=0D + @param Microcode Pointer to the microcode entry.=0D +**/=0D +VOID=0D +EFIAPI=0D +LoadMicrocode (=0D + IN CPU_MICROCODE_HEADER *Microcode=0D + )=0D +{=0D + ASSERT (Microcode !=3D NULL);=0D +=0D + AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG, (UINT64) (UINTN) (Microcode + 1)= );=0D +}=0D +=0D +/**=0D + Determine if a microcode patch matchs the specific processor signature a= nd flag.=0D +=0D + @param[in] ProcessorSignature The processor signature field value in= a=0D + microcode patch.=0D + @param[in] ProcessorFlags The processor flags field value in a=0D + microcode patch.=0D + @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MIC= ROCODE_CPU_ID=0D + structures.=0D + @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId a= rray.=0D +=0D + @retval TRUE The specified microcode patch matches to one of the Mic= rocodeCpuId.=0D + @retval FALSE The specified microcode patch doesn't match to any of t= he MicrocodeCpuId.=0D +**/=0D +BOOLEAN=0D +IsProcessorMatchedMicrocode (=0D + IN UINT32 ProcessorSignature,=0D + IN UINT32 ProcessorFlags,=0D + IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId,=0D + IN UINTN MicrocodeCpuIdCount=0D + )=0D +{=0D + UINTN Index;=0D +=0D + if (MicrocodeCpuIdCount =3D=3D 0) {=0D + return TRUE;=0D + }=0D +=0D + for (Index =3D 0; Index < MicrocodeCpuIdCount; Index++) {=0D + if ((ProcessorSignature =3D=3D MicrocodeCpuId[Index].ProcessorSignatur= e) &&=0D + (ProcessorFlags & (1 << MicrocodeCpuId[Index].PlatformId)) !=3D 0)= {=0D + return TRUE;=0D + }=0D + }=0D +=0D + return FALSE;=0D +}=0D +=0D +/**=0D + Detect whether specified processor can find matching microcode patch and= load it.=0D +=0D + Microcode format is as below:=0D + +----------------------------------------+------------------------------= -------------------+=0D + | CPU_MICROCODE_HEADER | = |=0D + +----------------------------------------+ = V=0D + | Update Data | = CPU_MICROCODE_HEADER.Checksum=0D + +----------------------------------------+-------+ = ^=0D + | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | = |=0D + +----------------------------------------+ V = |=0D + | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE= _HEADER.Checksum |=0D + | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ = |=0D + | ... | | = |=0D + +----------------------------------------+-------+----------------------= -------------------+=0D +=0D + There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.=0D + The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignat= ureCount=0D + of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.=0D +=0D + If Microcode is NULL, then ASSERT.=0D +=0D + @param Microcode Pointer to a microcode entry.=0D + @param MicrocodeLength The total length of the microcode entry.=0D + @param MinimumRevision The microcode whose revision <=3D MinimumRev= ision is treated as invalid.=0D + Caller can supply value get from GetProcesso= rMicrocodeSignature() to check=0D + whether the microcode is newer than loaded o= ne.=0D + Caller can supply 0 to treat any revision (e= xcept 0) microcode as valid.=0D + @param MicrocodeCpuIds Pointer to an array of processor signature a= nd platform ID that represents=0D + a set of processors.=0D + Caller can supply zero-element array to skip= the processor signature and=0D + platform ID check.=0D + @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.=0D + @param VerifyChecksum FALSE to skip all the checksum verifications= .=0D +=0D + @retval TRUE The microcode is valid.=0D + @retval FALSE The microcode is invalid.=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsValidMicrocode (=0D + IN CPU_MICROCODE_HEADER *Microcode,=0D + IN UINTN MicrocodeLength,=0D + IN UINT32 MinimumRevision,=0D + IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,=0D + IN UINTN MicrocodeCpuIdCount,=0D + IN BOOLEAN VerifyChecksum=0D + )=0D +{=0D + UINTN Index;=0D + UINT32 DataSize;=0D + UINT32 TotalSize;=0D + CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;=0D + CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;=0D + UINT32 ExtendedTableLength;=0D + UINT32 Sum32;=0D + BOOLEAN Match;=0D +=0D + ASSERT (Microcode !=3D NULL);=0D +=0D + //=0D + // It's invalid when:=0D + // the input microcode buffer is so small that even cannot contain the= header.=0D + // the input microcode buffer is so large that exceeds MAX_ADDRESS.=0D + //=0D + if ((MicrocodeLength < sizeof (CPU_MICROCODE_HEADER)) || (MicrocodeLengt= h > (MAX_ADDRESS - (UINTN) Microcode))) {=0D + return FALSE;=0D + }=0D +=0D + //=0D + // Per SDM, HeaderVersion and LoaderRevision should both be 1.=0D + //=0D + if ((Microcode->HeaderVersion !=3D 1) || (Microcode->LoaderRevision !=3D= 1)) {=0D + return FALSE;=0D + }=0D +=0D + //=0D + // The microcode revision should be larger than the minimum revision.=0D + //=0D + if (Microcode->UpdateRevision <=3D MinimumRevision) {=0D + return FALSE;=0D + }=0D +=0D + DataSize =3D Microcode->DataSize;=0D + if (DataSize =3D=3D 0) {=0D + DataSize =3D 2000;=0D + }=0D +=0D + //=0D + // Per SDM, DataSize should be multiple of DWORDs.=0D + //=0D + if ((DataSize % 4) !=3D 0) {=0D + return FALSE;=0D + }=0D +=0D + TotalSize =3D GetMicrocodeLength (Microcode);=0D +=0D + //=0D + // Check whether the whole microcode is within the buffer.=0D + // TotalSize should be multiple of 1024.=0D + //=0D + if (((TotalSize % SIZE_1KB) !=3D 0) || (TotalSize > MicrocodeLength)) {= =0D + return FALSE;=0D + }=0D +=0D + //=0D + // The summation of all DWORDs in microcode should be zero.=0D + //=0D + if (VerifyChecksum && (CalculateSum32 ((UINT32 *) Microcode, TotalSize) = !=3D 0)) {=0D + return FALSE;=0D + }=0D +=0D + Sum32 =3D Microcode->ProcessorSignature.Uint32 + Microcode->ProcessorFla= gs + Microcode->Checksum;=0D +=0D + //=0D + // Check the processor signature and platform ID in the primary header.= =0D + //=0D + Match =3D IsProcessorMatchedMicrocode (=0D + Microcode->ProcessorSignature.Uint32,=0D + Microcode->ProcessorFlags,=0D + MicrocodeCpuIds,=0D + MicrocodeCpuIdCount=0D + );=0D + if (Match) {=0D + return TRUE;=0D + }=0D +=0D + ExtendedTableLength =3D TotalSize - (DataSize + sizeof (CPU_MICROCODE_HE= ADER));=0D + if ((ExtendedTableLength < sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))= || ((ExtendedTableLength % 4) !=3D 0)) {=0D + return FALSE;=0D + }=0D + //=0D + // Extended Table exist, check if the CPU in support list=0D + //=0D + ExtendedTableHeader =3D (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINTN)= (Microcode + 1) + DataSize);=0D + if (ExtendedTableHeader->ExtendedSignatureCount > MAX_UINT32 / sizeof (C= PU_MICROCODE_EXTENDED_TABLE)) {=0D + return FALSE;=0D + }=0D + if (ExtendedTableHeader->ExtendedSignatureCount * sizeof (CPU_MICROCODE_= EXTENDED_TABLE)=0D + > ExtendedTableLength - sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)= ) {=0D + return FALSE;=0D + }=0D + //=0D + // Check the extended table checksum=0D + //=0D + if (VerifyChecksum && (CalculateSum32 ((UINT32 *) ExtendedTableHeader, E= xtendedTableLength) !=3D 0)) {=0D + return FALSE;=0D + }=0D +=0D + ExtendedTable =3D (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader = + 1);=0D + for (Index =3D 0; Index < ExtendedTableHeader->ExtendedSignatureCount; I= ndex ++) {=0D + if (VerifyChecksum &&=0D + (ExtendedTable[Index].ProcessorSignature.Uint32 + ExtendedTable[In= dex].ProcessorFlag=0D + + ExtendedTable[Index].Checksum !=3D Sum32)) {=0D + //=0D + // The extended table entry is valid when the summation of Processor= Signature, Processor Flags=0D + // and Checksum equal to the coresponding summation from primary hea= der. Because:=0D + // CalculateSum32 (Header + Update Binary) =3D=3D 0=0D + // CalculateSum32 (Header + Update Binary)=0D + // - (Header.ProcessorSignature + Header.ProcessorFlag + Head= er.Checksum)=0D + // + (Extended.ProcessorSignature + Extended.ProcessorFlag + = Extended.Checksum) =3D=3D 0=0D + // So,=0D + // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Che= cksum)=0D + // =3D=3D (Extended.ProcessorSignature + Extended.ProcessorFlag = + Extended.Checksum)=0D + //=0D + continue;=0D + }=0D + Match =3D IsProcessorMatchedMicrocode (=0D + ExtendedTable[Index].ProcessorSignature.Uint32,=0D + ExtendedTable[Index].ProcessorFlag,=0D + MicrocodeCpuIds,=0D + MicrocodeCpuIdCount=0D + );=0D + if (Match) {=0D + return TRUE;=0D + }=0D + }=0D + return FALSE;=0D +}=0D diff --git a/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf b/UefiCpuPkg/= Library/MicrocodeLib/MicrocodeLib.inf new file mode 100644 index 0000000000..c6f8f52e95 --- /dev/null +++ b/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf @@ -0,0 +1,32 @@ +## @file=0D +# Library for microcode verification and load.=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010006=0D + BASE_NAME =3D MicrocodeLib=0D + FILE_GUID =3D EB8C72BC-8A48-4F80-996B-E52F68416D57= =0D + MODULE_TYPE =3D BASE=0D + VERSION_STRING =3D 1.0=0D + LIBRARY_CLASS =3D MicrocodeLib=0D +=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64 EBC=0D +#=0D +=0D +[Sources.common]=0D + MicrocodeLib.c=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + UefiCpuPkg/UefiCpuPkg.dec=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + DebugLib=0D diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index a639ce5412..62acb291f3 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -1,7 +1,7 @@ ## @file UefiCpuPkg.dec=0D # This Package provides UEFI compatible CPU modules and libraries.=0D #=0D -# Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>=0D +# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>=0D #=0D # SPDX-License-Identifier: BSD-2-Clause-Patent=0D #=0D @@ -59,6 +59,9 @@ [LibraryClasses.IA32, LibraryClasses.X64] ## @libraryclass Provides function to get CPU cache information.=0D CpuCacheInfoLib|Include/Library/CpuCacheInfoLib.h=0D =0D + ## @libraryclass Provides function for loading microcode.=0D + MicrocodeLib|Include/Library/MicrocodeLib.h=0D +=0D [Guids]=0D gUefiCpuPkgTokenSpaceGuid =3D { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa,= 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}=0D gMsegSmramGuid =3D { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1,= 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}=0D diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 98c4c53465..b932cf63ec 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -60,6 +60,7 @@ [LibraryClasses] PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeC= offExtraActionLibNull.inf=0D TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurem= entLibNull.inf=0D VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf=0D + MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf=0D =0D [LibraryClasses.common.SEC]=0D PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.= inf=0D --=20 2.27.0.windows.1
|
|
Laszlo Ersek
On 04/02/21 07:58, Ni, Ray wrote:
Signed-off-by: Ray Ni <ray.ni@intel.com>With the BZ ref added: Acked-by: Laszlo Ersek <lersek@redhat.com> Thanks Laszlo diff --git a/UefiCpuPkg/Include/Library/MicrocodeLib.h b/UefiCpuPkg/Include/Library/MicrocodeLib.h
|
|
Dong, Eric
Reviewed-by: Eric Dong <eric.dong@intel.com>
toggle quoted messageShow quoted text
-----Original Message-----
From: Ni, Ray <ray.ni@intel.com> Sent: Friday, April 2, 2021 1:58 PM To: devel@edk2.groups.io Cc: Dong, Eric <eric.dong@intel.com>; Laszlo Ersek <lersek@redhat.com>; Kumar, Rahul1 <rahul1.kumar@intel.com> Subject: [PATCH 1/4] UefiCpuPkg: Add MicrocodeLib for loading microcode Signed-off-by: Ray Ni <ray.ni@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> --- UefiCpuPkg/Include/Library/MicrocodeLib.h | 120 +++++++ .../Library/MicrocodeLib/MicrocodeLib.c | 322 ++++++++++++++++++ .../Library/MicrocodeLib/MicrocodeLib.inf | 32 ++ UefiCpuPkg/UefiCpuPkg.dec | 5 +- UefiCpuPkg/UefiCpuPkg.dsc | 1 + 5 files changed, 479 insertions(+), 1 deletion(-) create mode 100644 UefiCpuPkg/Include/Library/MicrocodeLib.h create mode 100644 UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c create mode 100644 UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf diff --git a/UefiCpuPkg/Include/Library/MicrocodeLib.h b/UefiCpuPkg/Include/Library/MicrocodeLib.h new file mode 100644 index 0000000000..2570c43cce --- /dev/null +++ b/UefiCpuPkg/Include/Library/MicrocodeLib.h @@ -0,0 +1,120 @@ +/** @file + Public include file for Microcode library. + + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __MICROCODE_LIB_H__ +#define __MICROCODE_LIB_H__ + +#include <Register/Intel/Microcode.h> +#include <Ppi/ShadowMicrocode.h> + +/** + Get microcode update signature of currently loaded microcode update. + + @return Microcode signature. +**/ +UINT32 +EFIAPI +GetProcessorMicrocodeSignature ( + VOID + ); + +/** + Get the processor signature and platform ID for current processor. + + @param MicrocodeCpuId Return the processor signature and platform ID. +**/ +VOID +EFIAPI +GetProcessorMicrocodeCpuId ( + EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId + ); + +/** + Return the total size of the microcode entry. + + Logic follows pseudo code in SDM as below: + + N = 512 + If (Update.DataSize != 00000000H) + N = Update.TotalSize / 4 + + If Microcode is NULL, then ASSERT. + + @param Microcode Pointer to the microcode entry. + + @return The microcode total size. +**/ +UINT32 +EFIAPI +GetMicrocodeLength ( + IN CPU_MICROCODE_HEADER *Microcode + ); + +/** + Load the microcode to the processor. + + If Microcode is NULL, then ASSERT. + + @param Microcode Pointer to the microcode entry. +**/ +VOID +EFIAPI +LoadMicrocode ( + IN CPU_MICROCODE_HEADER *Microcode + ); + +/** + Detect whether specified processor can find matching microcode patch and load it. + + Microcode format is as below: + +----------------------------------------+-------------------------------------------------+ + | CPU_MICROCODE_HEADER | | + +----------------------------------------+ V + | Update Data | CPU_MICROCODE_HEADER.Checksum + +----------------------------------------+-------+ ^ + | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | | + +----------------------------------------+ V | + | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum | + | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ | + | ... | | | + +----------------------------------------+-------+-----------------------------------------+ + + There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format. + The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount + of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure. + + If Microcode is NULL, then ASSERT. + + @param Microcode Pointer to a microcode entry. + @param MicrocodeLength The total length of the microcode entry. + @param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid. + Caller can supply value get from GetProcessorMicrocodeSignature() to check + whether the microcode is newer than loaded one. + Caller can supply 0 to treat any revision (except 0) microcode as valid. + @param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents + a set of processors. + Caller can supply zero-element array to skip the processor signature and + platform ID check. + @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds. + @param VerifyChecksum FALSE to skip all the checksum verifications. + + @retval TRUE The microcode is valid. + @retval FALSE The microcode is invalid. +**/ +BOOLEAN +EFIAPI +IsValidMicrocode ( + IN CPU_MICROCODE_HEADER *Microcode, + IN UINTN MicrocodeLength, + IN UINT32 MinimumRevision, + IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds, + IN UINTN MicrocodeCpuIdCount, + IN BOOLEAN VerifyChecksum + ); + +#endif \ No newline at end of file diff --git a/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c b/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c new file mode 100644 index 0000000000..03a43fdae7 --- /dev/null +++ b/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c @@ -0,0 +1,322 @@ +/** @file + Implementation of MicrocodeLib. + + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi/UefiBaseType.h> +#include <Register/Intel/Cpuid.h> +#include <Register/Intel/ArchitecturalMsr.h> +#include <Register/Intel/Microcode.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Ppi/ShadowMicrocode.h> + +/** + Get microcode update signature of currently loaded microcode update. + + @return Microcode signature. +**/ +UINT32 +EFIAPI +GetProcessorMicrocodeSignature ( + VOID + ) +{ + MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr; + + AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0); + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL); + BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID); + return BiosSignIdMsr.Bits.MicrocodeUpdateSignature; +} + +/** + Get the processor signature and platform ID for current processor. + + @param MicrocodeCpuId Return the processor signature and platform ID. +**/ +VOID +EFIAPI +GetProcessorMicrocodeCpuId ( + EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId + ) +{ + MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr; + + ASSERT (MicrocodeCpuId != NULL); + + PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID); + MicrocodeCpuId->PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId; + AsmCpuid (CPUID_VERSION_INFO, &MicrocodeCpuId->ProcessorSignature, NULL, NULL, NULL); +} + +/** + Return the total size of the microcode entry. + + Logic follows pseudo code in SDM as below: + + N = 512 + If (Update.DataSize != 00000000H) + N = Update.TotalSize / 4 + + If Microcode is NULL, then ASSERT. + + @param Microcode Pointer to the microcode entry. + + @return The microcode total size. +**/ +UINT32 +EFIAPI +GetMicrocodeLength ( + IN CPU_MICROCODE_HEADER *Microcode + ) +{ + UINT32 TotalSize; + + ASSERT (Microcode != NULL); + + TotalSize = 2048; + if (Microcode->DataSize != 0) { + TotalSize = Microcode->TotalSize; + } + return TotalSize; +} + +/** + Load the microcode to the processor. + + If Microcode is NULL, then ASSERT. + + @param Microcode Pointer to the microcode entry. +**/ +VOID +EFIAPI +LoadMicrocode ( + IN CPU_MICROCODE_HEADER *Microcode + ) +{ + ASSERT (Microcode != NULL); + + AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG, (UINT64) (UINTN) (Microcode + 1)); +} + +/** + Determine if a microcode patch matchs the specific processor signature and flag. + + @param[in] ProcessorSignature The processor signature field value in a + microcode patch. + @param[in] ProcessorFlags The processor flags field value in a + microcode patch. + @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID + structures. + @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array. + + @retval TRUE The specified microcode patch matches to one of the MicrocodeCpuId. + @retval FALSE The specified microcode patch doesn't match to any of the MicrocodeCpuId. +**/ +BOOLEAN +IsProcessorMatchedMicrocode ( + IN UINT32 ProcessorSignature, + IN UINT32 ProcessorFlags, + IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId, + IN UINTN MicrocodeCpuIdCount + ) +{ + UINTN Index; + + if (MicrocodeCpuIdCount == 0) { + return TRUE; + } + + for (Index = 0; Index < MicrocodeCpuIdCount; Index++) { + if ((ProcessorSignature == MicrocodeCpuId[Index].ProcessorSignature) && + (ProcessorFlags & (1 << MicrocodeCpuId[Index].PlatformId)) != 0) { + return TRUE; + } + } + + return FALSE; +} + +/** + Detect whether specified processor can find matching microcode patch and load it. + + Microcode format is as below: + +----------------------------------------+-------------------------------------------------+ + | CPU_MICROCODE_HEADER | | + +----------------------------------------+ V + | Update Data | CPU_MICROCODE_HEADER.Checksum + +----------------------------------------+-------+ ^ + | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | | + +----------------------------------------+ V | + | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum | + | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ | + | ... | | | + +----------------------------------------+-------+-----------------------------------------+ + + There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format. + The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount + of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure. + + If Microcode is NULL, then ASSERT. + + @param Microcode Pointer to a microcode entry. + @param MicrocodeLength The total length of the microcode entry. + @param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid. + Caller can supply value get from GetProcessorMicrocodeSignature() to check + whether the microcode is newer than loaded one. + Caller can supply 0 to treat any revision (except 0) microcode as valid. + @param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents + a set of processors. + Caller can supply zero-element array to skip the processor signature and + platform ID check. + @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds. + @param VerifyChecksum FALSE to skip all the checksum verifications. + + @retval TRUE The microcode is valid. + @retval FALSE The microcode is invalid. +**/ +BOOLEAN +EFIAPI +IsValidMicrocode ( + IN CPU_MICROCODE_HEADER *Microcode, + IN UINTN MicrocodeLength, + IN UINT32 MinimumRevision, + IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds, + IN UINTN MicrocodeCpuIdCount, + IN BOOLEAN VerifyChecksum + ) +{ + UINTN Index; + UINT32 DataSize; + UINT32 TotalSize; + CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; + CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; + UINT32 ExtendedTableLength; + UINT32 Sum32; + BOOLEAN Match; + + ASSERT (Microcode != NULL); + + // + // It's invalid when: + // the input microcode buffer is so small that even cannot contain the header. + // the input microcode buffer is so large that exceeds MAX_ADDRESS. + // + if ((MicrocodeLength < sizeof (CPU_MICROCODE_HEADER)) || (MicrocodeLength > (MAX_ADDRESS - (UINTN) Microcode))) { + return FALSE; + } + + // + // Per SDM, HeaderVersion and LoaderRevision should both be 1. + // + if ((Microcode->HeaderVersion != 1) || (Microcode->LoaderRevision != 1)) { + return FALSE; + } + + // + // The microcode revision should be larger than the minimum revision. + // + if (Microcode->UpdateRevision <= MinimumRevision) { + return FALSE; + } + + DataSize = Microcode->DataSize; + if (DataSize == 0) { + DataSize = 2000; + } + + // + // Per SDM, DataSize should be multiple of DWORDs. + // + if ((DataSize % 4) != 0) { + return FALSE; + } + + TotalSize = GetMicrocodeLength (Microcode); + + // + // Check whether the whole microcode is within the buffer. + // TotalSize should be multiple of 1024. + // + if (((TotalSize % SIZE_1KB) != 0) || (TotalSize > MicrocodeLength)) { + return FALSE; + } + + // + // The summation of all DWORDs in microcode should be zero. + // + if (VerifyChecksum && (CalculateSum32 ((UINT32 *) Microcode, TotalSize) != 0)) { + return FALSE; + } + + Sum32 = Microcode->ProcessorSignature.Uint32 + Microcode->ProcessorFlags + Microcode->Checksum; + + // + // Check the processor signature and platform ID in the primary header. + // + Match = IsProcessorMatchedMicrocode ( + Microcode->ProcessorSignature.Uint32, + Microcode->ProcessorFlags, + MicrocodeCpuIds, + MicrocodeCpuIdCount + ); + if (Match) { + return TRUE; + } + + ExtendedTableLength = TotalSize - (DataSize + sizeof (CPU_MICROCODE_HEADER)); + if ((ExtendedTableLength < sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) || ((ExtendedTableLength % 4) != 0)) { + return FALSE; + } + // + // Extended Table exist, check if the CPU in support list + // + ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINTN) (Microcode + 1) + DataSize); + if (ExtendedTableHeader->ExtendedSignatureCount > MAX_UINT32 / sizeof (CPU_MICROCODE_EXTENDED_TABLE)) { + return FALSE; + } + if (ExtendedTableHeader->ExtendedSignatureCount * sizeof (CPU_MICROCODE_EXTENDED_TABLE) + > ExtendedTableLength - sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) { + return FALSE; + } + // + // Check the extended table checksum + // + if (VerifyChecksum && (CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength) != 0)) { + return FALSE; + } + + ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1); + for (Index = 0; Index < ExtendedTableHeader->ExtendedSignatureCount; Index ++) { + if (VerifyChecksum && + (ExtendedTable[Index].ProcessorSignature.Uint32 + ExtendedTable[Index].ProcessorFlag + + ExtendedTable[Index].Checksum != Sum32)) { + // + // The extended table entry is valid when the summation of Processor Signature, Processor Flags + // and Checksum equal to the coresponding summation from primary header. Because: + // CalculateSum32 (Header + Update Binary) == 0 + // CalculateSum32 (Header + Update Binary) + // - (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum) + // + (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum) == 0 + // So, + // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum) + // == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum) + // + continue; + } + Match = IsProcessorMatchedMicrocode ( + ExtendedTable[Index].ProcessorSignature.Uint32, + ExtendedTable[Index].ProcessorFlag, + MicrocodeCpuIds, + MicrocodeCpuIdCount + ); + if (Match) { + return TRUE; + } + } + return FALSE; +} diff --git a/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf b/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf new file mode 100644 index 0000000000..c6f8f52e95 --- /dev/null +++ b/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf @@ -0,0 +1,32 @@ +## @file +# Library for microcode verification and load. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = MicrocodeLib + FILE_GUID = EB8C72BC-8A48-4F80-996B-E52F68416D57 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MicrocodeLib + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + MicrocodeLib.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index a639ce5412..62acb291f3 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -1,7 +1,7 @@ ## @file UefiCpuPkg.dec # This Package provides UEFI compatible CPU modules and libraries. # -# Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR> # # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -59,6 +59,9 @@ [LibraryClasses.IA32, LibraryClasses.X64] ## @libraryclass Provides function to get CPU cache information. CpuCacheInfoLib|Include/Library/CpuCacheInfoLib.h + ## @libraryclass Provides function for loading microcode. + MicrocodeLib|Include/Library/MicrocodeLib.h + [Guids] gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }} gMsegSmramGuid = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }} diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 98c4c53465..b932cf63ec 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -60,6 +60,7 @@ [LibraryClasses] PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf + MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf [LibraryClasses.common.SEC] PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf -- 2.27.0.windows.1
|
|