summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg
diff options
context:
space:
mode:
authorRay Ni <ray.ni@intel.com>2021-04-01 18:32:23 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2021-04-09 01:43:18 +0000
commit1a957f17bc62771df7517135c0e50052fc924ade (patch)
tree4e776c1090843cd127a34b5040e91b8b6e1e2a7d /UefiCpuPkg
parent19d5bccc7663399c0726aac800ddd4591be0176a (diff)
downloadedk2-1a957f17bc62771df7517135c0e50052fc924ade.tar.gz
edk2-1a957f17bc62771df7517135c0e50052fc924ade.tar.bz2
edk2-1a957f17bc62771df7517135c0e50052fc924ade.zip
UefiCpuPkg: Add MicrocodeLib for loading microcode
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3303 Signed-off-by: Ray Ni <ray.ni@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Acked-by: Laszlo Ersek <lersek@redhat.com> Cc: Rahul Kumar <rahul1.kumar@intel.com>
Diffstat (limited to 'UefiCpuPkg')
-rw-r--r--UefiCpuPkg/Include/Library/MicrocodeLib.h120
-rw-r--r--UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c322
-rw-r--r--UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf32
-rw-r--r--UefiCpuPkg/UefiCpuPkg.dec5
-rw-r--r--UefiCpuPkg/UefiCpuPkg.dsc2
5 files changed, 480 insertions, 1 deletions
diff --git a/UefiCpuPkg/Include/Library/MicrocodeLib.h b/UefiCpuPkg/Include/Library/MicrocodeLib.h
new file mode 100644
index 0000000000..f14d56ba5f
--- /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
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 @@
## @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 c16cf8d1b9..699c91626b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -60,6 +60,7 @@
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
@@ -147,6 +148,7 @@
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.inf
+ UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
UefiCpuPkg/Library/MtrrLib/MtrrLib.inf
UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.inf