[edk2-devel] [PATCH 1/4] UefiCpuPkg: Add MicrocodeLib for loading microcode

Dong, Eric eric.dong at intel.com
Thu Apr 8 02:19:58 UTC 2021


Reviewed-by: Eric Dong <eric.dong at intel.com>

-----Original Message-----
From: Ni, Ray <ray.ni at intel.com> 
Sent: Friday, April 2, 2021 1:58 PM
To: devel at edk2.groups.io
Cc: Dong, Eric <eric.dong at intel.com>; Laszlo Ersek <lersek at redhat.com>; Kumar, Rahul1 <rahul1.kumar at intel.com>
Subject: [PATCH 1/4] UefiCpuPkg: Add MicrocodeLib for loading microcode

Signed-off-by: Ray Ni <ray.ni at intel.com>
Cc: Eric Dong <eric.dong at intel.com>
Cc: Laszlo Ersek <lersek at redhat.com>
Cc: Rahul Kumar <rahul1.kumar at 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



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#73811): https://edk2.groups.io/g/devel/message/73811
Mute This Topic: https://groups.io/mt/81796731/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list