]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/MpInitLib: Add MicrocodeDetect() and load microcode on BSP
authorJeff Fan <jeff.fan@intel.com>
Wed, 20 Jul 2016 15:49:35 +0000 (23:49 +0800)
committerJeff Fan <jeff.fan@intel.com>
Wed, 17 Aug 2016 12:00:23 +0000 (20:00 +0800)
v4:
  1. ProcessorSignature is updated to CPU_MICROCODE_PROCESSOR_SIGNATURE
     instead of UINT32.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
UefiCpuPkg/Library/MpInitLib/Microcode.c [new file with mode: 0644]
UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/Library/MpInitLib/MpLib.h
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf

index e9a27250a78eaf2ba313aade20ede36ac85abb22..03a899451643c4ca8d05d126dcf792d3edd3c7cd 100644 (file)
@@ -39,6 +39,7 @@
   DxeMpLib.c\r
   MpLib.c\r
   MpLib.h\r
   DxeMpLib.c\r
   MpLib.c\r
   MpLib.h\r
+  Microcode.c\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r
diff --git a/UefiCpuPkg/Library/MpInitLib/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c
new file mode 100644 (file)
index 0000000..0fd8e8c
--- /dev/null
@@ -0,0 +1,216 @@
+/** @file\r
+  Implementation of loading microcode on processors.\r
+\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "MpLib.h"\r
+\r
+/**\r
+  Get microcode update signature of currently loaded microcode update.\r
+\r
+  @return  Microcode signature.\r
+**/\r
+UINT32\r
+GetCurrentMicrocodeSignature (\r
+  VOID\r
+  )\r
+{\r
+  MSR_IA32_BIOS_SIGN_ID_REGISTER   BiosSignIdMsr;\r
+\r
+  AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
+  BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);\r
+  return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;\r
+}\r
+\r
+/**\r
+  Detect whether specified processor can find matching microcode patch and load it.\r
+\r
+  @param[in] PeiCpuMpData        Pointer to PEI CPU MP Data\r
+**/\r
+VOID\r
+MicrocodeDetect (\r
+  IN CPU_MP_DATA             *CpuMpData\r
+  )\r
+{\r
+  UINT64                                  MicrocodePatchAddress;\r
+  UINT64                                  MicrocodePatchRegionSize;\r
+  UINT32                                  ExtendedTableLength;\r
+  UINT32                                  ExtendedTableCount;\r
+  CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;\r
+  CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;\r
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;\r
+  UINTN                                   MicrocodeEnd;\r
+  UINTN                                   Index;\r
+  UINT8                                   PlatformId;\r
+  CPUID_VERSION_INFO_EAX                  Eax;\r
+  UINT32                                  CurrentRevision;\r
+  UINT32                                  LatestRevision;\r
+  UINTN                                   TotalSize;\r
+  UINT32                                  CheckSum32;\r
+  BOOLEAN                                 CorrectMicrocode;\r
+  VOID                                    *MicrocodeData;\r
+  MSR_IA32_PLATFORM_ID_REGISTER           PlatformIdMsr;\r
+\r
+  MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
+  MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
+  if (MicrocodePatchRegionSize == 0) {\r
+    //\r
+    // There is no microcode patches\r
+    //\r
+    return;\r
+  }\r
+\r
+  CurrentRevision = GetCurrentMicrocodeSignature ();\r
+  if (CurrentRevision != 0) {\r
+    //\r
+    // Skip loading microcode if it has been loaded successfully\r
+    //\r
+    return;\r
+  }\r
+\r
+  ExtendedTableLength = 0;\r
+  //\r
+  // Here data of CPUID leafs have not been collected into context buffer, so\r
+  // GetProcessorCpuid() cannot be used here to retrieve sCPUID data.\r
+  //\r
+  AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);\r
+\r
+  //\r
+  // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
+  //\r
+  PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
+  PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
+\r
+  LatestRevision = 0;\r
+  MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);\r
+  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
+  do {\r
+    //\r
+    // Check if the microcode is for the Cpu and the version is newer\r
+    // and the update can be processed on the platform\r
+    //\r
+    CorrectMicrocode = FALSE;\r
+    if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
+      //\r
+      // It is the microcode header. It is not the padding data between microcode patches\r
+      // because the padding data should not include 0x00000001 and it should be the repeated\r
+      // byte format (like 0xXYXYXYXY....).\r
+      //\r
+      if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&\r
+          MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
+          (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
+          ) {\r
+        if (MicrocodeEntryPoint->DataSize == 0) {\r
+          CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);\r
+        } else {\r
+          CheckSum32 = CalculateSum32 (\r
+                         (UINT32 *) MicrocodeEntryPoint,\r
+                         MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)\r
+                         );\r
+        }\r
+        if (CheckSum32 == 0) {\r
+          CorrectMicrocode = TRUE;\r
+        }\r
+      } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
+                 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
+        ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +\r
+                                sizeof (CPU_MICROCODE_HEADER));\r
+        if (ExtendedTableLength != 0) {\r
+          //\r
+          // Extended Table exist, check if the CPU in support list\r
+          //\r
+          ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)\r
+                                  + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));\r
+          //\r
+          // Calculate Extended Checksum\r
+          //\r
+          if ((ExtendedTableLength % 4) == 0) {\r
+            CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);\r
+            if (CheckSum32 == 0) {\r
+              //\r
+              // Checksum correct\r
+              //\r
+              ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
+              ExtendedTable      = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
+              for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
+                CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
+                if (CheckSum32 == 0) {\r
+                  //\r
+                  // Verify Header\r
+                  //\r
+                  if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&\r
+                      (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {\r
+                    //\r
+                    // Find one\r
+                    //\r
+                    CorrectMicrocode = TRUE;\r
+                    break;\r
+                  }\r
+                }\r
+                ExtendedTable ++;\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+    } else {\r
+      //\r
+      // It is the padding data between the microcode patches for microcode patches alignment.\r
+      // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
+      // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
+      // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
+      // find the next possible microcode patch header.\r
+      //\r
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+      continue;\r
+    }\r
+    //\r
+    // Get the next patch.\r
+    //\r
+    if (MicrocodeEntryPoint->DataSize == 0) {\r
+      TotalSize = 2048;\r
+    } else {\r
+      TotalSize = MicrocodeEntryPoint->TotalSize;\r
+    }\r
+\r
+    if (CorrectMicrocode) {\r
+      LatestRevision = MicrocodeEntryPoint->UpdateRevision;\r
+      MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));\r
+    }\r
+\r
+    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
+  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
+\r
+  if (LatestRevision > CurrentRevision) {\r
+    //\r
+    // BIOS only authenticate updates that contain a numerically larger revision\r
+    // than the currently loaded revision, where Current Signature < New Update\r
+    // Revision. A processor with no loaded update is considered to have a\r
+    // revision equal to zero.\r
+    //\r
+    AsmWriteMsr64 (\r
+        MSR_IA32_BIOS_UPDT_TRIG,\r
+        (UINT64) (UINTN) MicrocodeData\r
+        );\r
+    //\r
+    // Get and check new microcode signature\r
+    //\r
+    CurrentRevision = GetCurrentMicrocodeSignature ();\r
+    if (CurrentRevision != LatestRevision) {\r
+      AcquireSpinLock(&CpuMpData->MpLock);\r
+      DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \\r
+                loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));\r
+      ReleaseSpinLock(&CpuMpData->MpLock);\r
+    }\r
+  }\r
+}\r
index 0832228d71cab1216e548eabbd208c2ac6c6bdd6..7384f5d0d2b6086528f064806286a9cc9a9de717 100644 (file)
@@ -294,6 +294,11 @@ MpInitLibInitialize (
     CpuMpData->CpuData[Index].StartupApSignal =\r
       (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
   }\r
     CpuMpData->CpuData[Index].StartupApSignal =\r
       (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
   }\r
+  //\r
+  // Load Microcode on BSP\r
+  //\r
+  MicrocodeDetect (CpuMpData);\r
+  //\r
   // Store BSP's MTRR setting\r
   //\r
   MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
   // Store BSP's MTRR setting\r
   //\r
   MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
index ca8bd445ba668d993c075a1dbada68d1e2617c0e..625d0612218e14de69b0da313d31731d1b49e45d 100644 (file)
@@ -232,5 +232,15 @@ AsmGetAddressMap (
   OUT MP_ASSEMBLY_ADDRESS_MAP    *AddressMap\r
   );\r
 \r
   OUT MP_ASSEMBLY_ADDRESS_MAP    *AddressMap\r
   );\r
 \r
+/**\r
+  Detect whether specified processor can find matching microcode patch and load it.\r
+\r
+  @param[in] PeiCpuMpData        Pointer to PEI CPU MP Data\r
+**/\r
+VOID\r
+MicrocodeDetect (\r
+  IN CPU_MP_DATA             *CpuMpData\r
+  );\r
+\r
 #endif\r
 \r
 #endif\r
 \r
index c195a38f59f44a74606e181a330fbb0962c0af15..0c6873da79db0dfe0b7be76f2f74e6da074df0c1 100644 (file)
@@ -39,6 +39,7 @@
   PeiMpLib.c\r
   MpLib.c\r
   MpLib.h\r
   PeiMpLib.c\r
   MpLib.c\r
   MpLib.h\r
+  Microcode.c\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r