]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/CpuMpPei: Load microcode on BSP and APs
authorJeff Fan <jeff.fan@intel.com>
Wed, 15 Jul 2015 03:40:41 +0000 (03:40 +0000)
committervanjeff <vanjeff@Edk2>
Wed, 15 Jul 2015 03:40:41 +0000 (03:40 +0000)
Add DetectMicrocode() to load microcode on BSP and APs.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18002 6f19259b-4bc3-4df7-8a09-765794883524

UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei/CpuMpPei.h
UefiCpuPkg/CpuMpPei/CpuMpPei.inf
UefiCpuPkg/CpuMpPei/Microcode.c [new file with mode: 0644]
UefiCpuPkg/CpuMpPei/Microcode.h [new file with mode: 0644]

index e39a813cdd189c8e4a6cbf039ec5411709352151..d63b1ff23111ac9d49fb5a87f3e482072aaa8906 100644 (file)
@@ -119,9 +119,10 @@ ApCFunction (
     PeiCpuMpData->CpuData[NumApsExecuting].ApicId        = GetInitialApicId ();
     PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;
     //
-    // Sync BSP's Mtrr table to all wakeup APs
+    // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
     //
     MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
+    MicrocodeDetect ();
   }
 
   //
@@ -288,7 +289,10 @@ CountProcessorNumber (
   IN PEI_CPU_MP_DATA            *PeiCpuMpData
   )
 {
-
+  //
+  // Load Microcode on BSP
+  //
+  MicrocodeDetect ();
   //
   // Store BSP's MTRR setting
   //
index 466ddc055838f37835d81b3e0207f7c3966d2be4..7a34a98242d8e517f2f377067fae706e9d4ce4fb 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <Ppi/SecPlatformInformation.h>
 
+#include <Register/LocalApic.h>
+
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
@@ -31,6 +33,9 @@
 #include <Library/SynchronizationLib.h>
 #include <Library/TimerLib.h>
 #include <Library/UefiCpuLib.h>
+
+#include "Microcode.h"
+
 //
 // AP state
 //
index e195f8c3d810caf90689faf78e13b1223a6cfe0a..1bb4daef2b63aca17f36e0eac6284f831045f42e 100644 (file)
@@ -30,6 +30,8 @@
 [Sources]
   CpuMpPei.h
   CpuMpPei.c
+  Microcode.h
+  Microcode.c
 
 [Sources.IA32]
   Ia32/MpEqu.inc
@@ -66,6 +68,8 @@
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize
 
 [Depex]
   gEfiPeiMemoryDiscoveredPpiGuid
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.c b/UefiCpuPkg/CpuMpPei/Microcode.c
new file mode 100644 (file)
index 0000000..eb2e76b
--- /dev/null
@@ -0,0 +1,200 @@
+/** @file
+  Implementation of loading microcode on processors.
+
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuMpPei.h"
+
+/**
+  Get microcode update signature of currently loaded microcode update.
+
+  @return  Microcode signature.
+
+**/
+UINT32
+GetCurrentMicrocodeSignature (
+  VOID
+  )
+{
+  UINT64 Signature;
+
+  AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
+  Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);
+  return (UINT32) RShiftU64 (Signature, 32);
+}
+
+/**
+  Detect whether specified processor can find matching microcode patch and load it.
+
+**/
+VOID
+MicrocodeDetect (
+  VOID
+  )
+{
+  UINT64                                  MicrocodePatchAddress;
+  UINT64                                  MicrocodePatchRegionSize;
+  UINT32                                  ExtendedTableLength;
+  UINT32                                  ExtendedTableCount;
+  EFI_CPU_MICROCODE_EXTENDED_TABLE        *ExtendedTable;
+  EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
+  EFI_CPU_MICROCODE_HEADER                *MicrocodeEntryPoint;
+  UINTN                                   MicrocodeEnd;
+  UINTN                                   Index;
+  UINT8                                   PlatformId;
+  UINT32                                  RegEax;
+  UINT32                                  LatestRevision;
+  UINTN                                   TotalSize;
+  UINT32                                  CheckSum32;
+  BOOLEAN                                 CorrectMicrocode;
+  INT32                                   CurrentSignature;
+  MICROCODE_INFO                          MicrocodeInfo;
+
+  ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
+  MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);
+  MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
+  if (MicrocodePatchRegionSize == 0) {
+    //
+    // There is no microcode patches
+    //
+    return;
+  }
+
+  ExtendedTableLength = 0;
+  //
+  // Here data of CPUID leafs have not been collected into context buffer, so
+  // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
+  //
+  AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+
+  //
+  // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
+  //
+  PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
+
+  LatestRevision = 0;
+  MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
+  MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
+  do {
+    //
+    // Check if the microcode is for the Cpu and the version is newer
+    // and the update can be processed on the platform
+    //
+    CorrectMicrocode = FALSE;
+    if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
+      //
+      // It is the microcode header. It is not the padding data between microcode patches
+      // becasue the padding data should not include 0x00000001 and it should be the repeated
+      // byte format (like 0xXYXYXYXY....).
+      //
+      if (MicrocodeEntryPoint->ProcessorId == RegEax &&
+          MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
+          (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
+          ) {
+        if (MicrocodeEntryPoint->DataSize == 0) {
+          CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
+        } else {
+          CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
+        }
+        if (CheckSum32 == 0) {
+          CorrectMicrocode = TRUE;
+        }
+      } else if ((MicrocodeEntryPoint->DataSize != 0) &&
+                 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
+        ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+        if (ExtendedTableLength != 0) {
+          //
+          // Extended Table exist, check if the CPU in support list
+          //
+          ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+          //
+          // Calculate Extended Checksum
+          //
+          if ((ExtendedTableLength % 4) == 0) {
+            CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
+            if (CheckSum32 == 0) {
+              //
+              // Checksum correct
+              //
+              ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
+              ExtendedTable      = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+              for (Index = 0; Index < ExtendedTableCount; Index ++) {
+                CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
+                if (CheckSum32 == 0) {
+                  //
+                  // Verify Header
+                  //
+                  if ((ExtendedTable->ProcessorSignature == RegEax) &&
+                      (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
+                    //
+                    // Find one
+                    //
+                    CorrectMicrocode = TRUE;
+                    break;
+                  }
+                }
+                ExtendedTable ++;
+              }
+            }
+          }
+        }
+      }
+    } else {
+      //
+      // It is the padding data between the microcode patches for microcode patches alignment.
+      // Because the microcode patch is the multiple of 1-KByte, the padding 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 = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+      continue;
+    }
+    //
+    // Get the next patch.
+    //
+    if (MicrocodeEntryPoint->DataSize == 0) {
+      TotalSize = 2048;
+    } else {
+      TotalSize = MicrocodeEntryPoint->TotalSize;
+    }
+
+    if (CorrectMicrocode) {
+      LatestRevision = MicrocodeEntryPoint->UpdateRevision;
+      MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
+      MicrocodeInfo.MicrocodeSize = TotalSize;
+      MicrocodeInfo.ProcessorId = RegEax;
+    }
+
+    MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
+  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
+
+  if (LatestRevision > 0) {
+    //
+    // Get microcode update signature of currently loaded microcode update
+    //
+    CurrentSignature = GetCurrentMicrocodeSignature ();
+    //
+    // If no microcode update has been loaded, then trigger microcode load.
+    //
+    if (CurrentSignature == 0) {
+      AsmWriteMsr64 (
+        EFI_MSR_IA32_BIOS_UPDT_TRIG,
+        (UINT64) (UINTN) MicrocodeInfo.MicrocodeData
+        );
+      MicrocodeInfo.Load = TRUE;
+    } else {
+      MicrocodeInfo.Load = FALSE;
+    }
+  }
+}
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.h b/UefiCpuPkg/CpuMpPei/Microcode.h
new file mode 100644 (file)
index 0000000..6f93e2f
--- /dev/null
@@ -0,0 +1,68 @@
+/** @file
+  Definitions for loading microcode on processors.
+
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _CPU_MICROCODE_H_
+#define _CPU_MICROCODE_H_
+
+#define EFI_MSR_IA32_PLATFORM_ID         0x17
+#define EFI_MSR_IA32_BIOS_UPDT_TRIG      0x79
+#define EFI_MSR_IA32_BIOS_SIGN_ID        0x8b
+
+#define MAX_MICROCODE_DESCRIPTOR_LENGTH  100
+
+typedef struct {
+  VOID     *MicrocodeData;
+  UINTN    MicrocodeSize;
+  UINT32   ProcessorId;
+  BOOLEAN  Load;
+} MICROCODE_INFO;
+
+//
+// Definition for IA32 microcode format
+//
+typedef struct {
+  UINT32  HeaderVersion;
+  UINT32  UpdateRevision;
+  UINT32  Date;
+  UINT32  ProcessorId;
+  UINT32  Checksum;
+  UINT32  LoaderRevision;
+  UINT32  ProcessorFlags;
+  UINT32  DataSize;
+  UINT32  TotalSize;
+  UINT8   Reserved[12];
+} EFI_CPU_MICROCODE_HEADER;
+
+typedef struct {
+  UINT32  ExtendedSignatureCount;
+  UINT32  ExtendedTableChecksum;
+  UINT8   Reserved[12];
+} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER;
+
+typedef struct {
+  UINT32  ProcessorSignature;
+  UINT32  ProcessorFlag;
+  UINT32  ProcessorChecksum;
+} EFI_CPU_MICROCODE_EXTENDED_TABLE;
+
+/**
+  Detect whether specified processor can find matching microcode patch and load it.
+
+**/
+VOID
+MicrocodeDetect (
+  VOID
+  );
+
+#endif