]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/Microcode.c
UefiCpuPkg/Microcode.c: Add verification before calculate CheckSum32
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
index 5bb0145c87f04fe103a85be761d135e37dbc036d..643a6f94f4a5fb1d0aee99f1da954bf12f8f96be 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Implementation of loading microcode on processors.\r
 \r
-  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2015 - 2018, 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
@@ -35,15 +35,51 @@ GetCurrentMicrocodeSignature (
 /**\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
+  Microcode Payload as the following format:\r
+  +----------------------------------------+------------------+\r
+  |          CPU_MICROCODE_HEADER          |                  |\r
+  +----------------------------------------+  CheckSum Part1  |\r
+  |            Microcode Binary            |                  |\r
+  +----------------------------------------+------------------+\r
+  |  CPU_MICROCODE_EXTENDED_TABLE_HEADER   |                  |\r
+  +----------------------------------------+  CheckSum Part2  |\r
+  |      CPU_MICROCODE_EXTENDED_TABLE      |                  |\r
+  |                   ...                  |                  |\r
+  +----------------------------------------+------------------+\r
+\r
+  There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.\r
+  The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount\r
+  of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.\r
+\r
+  When we are trying to verify the CheckSum32 with extended table.\r
+  We should use the fields of exnteded table to replace the corresponding\r
+  fields in CPU_MICROCODE_HEADER structure, and recalculate the\r
+  CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named\r
+  it as CheckSum Part3.\r
+\r
+  The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER\r
+  and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2\r
+  is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.\r
+\r
+  Only ProcessorSignature, ProcessorFlag and CheckSum are different between\r
+  CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.\r
+  Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
+  When we are going to calculate CheckSum32, just should use the corresponding part\r
+  of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.\r
+\r
+  Notes: CheckSum32 is not a strong verification.\r
+         It does not guarantee that the data has not been modified.\r
+         CPU has its own mechanism to verify Microcode Binary part.\r
+\r
+  @param[in]  CpuMpData    The pointer to CPU MP Data structure.\r
+  @param[in]  IsBspCallIn  Indicate whether the caller is BSP or not.\r
 **/\r
 VOID\r
 MicrocodeDetect (\r
-  IN CPU_MP_DATA             *CpuMpData\r
+  IN CPU_MP_DATA             *CpuMpData,\r
+  IN BOOLEAN                 IsBspCallIn\r
   )\r
 {\r
-  UINT64                                  MicrocodePatchAddress;\r
-  UINT64                                  MicrocodePatchRegionSize;\r
   UINT32                                  ExtendedTableLength;\r
   UINT32                                  ExtendedTableCount;\r
   CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;\r
@@ -57,13 +93,19 @@ MicrocodeDetect (
   UINT32                                  LatestRevision;\r
   UINTN                                   TotalSize;\r
   UINT32                                  CheckSum32;\r
+  UINT32                                  InCompleteCheckSum32;\r
   BOOLEAN                                 CorrectMicrocode;\r
   VOID                                    *MicrocodeData;\r
   MSR_IA32_PLATFORM_ID_REGISTER           PlatformIdMsr;\r
+  UINT32                                  ProcessorFlags;\r
+  UINT32                                  ThreadId;\r
 \r
-  MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
-  MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
-  if (MicrocodePatchRegionSize == 0) {\r
+  //\r
+  // set ProcessorFlags to suppress incorrect compiler/analyzer warnings\r
+  //\r
+  ProcessorFlags = 0;\r
+\r
+  if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
     //\r
     // There is no microcode patches\r
     //\r
@@ -71,17 +113,25 @@ MicrocodeDetect (
   }\r
 \r
   CurrentRevision = GetCurrentMicrocodeSignature ();\r
-  if (CurrentRevision != 0) {\r
+  if (CurrentRevision != 0 && !IsBspCallIn) {\r
     //\r
     // Skip loading microcode if it has been loaded successfully\r
     //\r
     return;\r
   }\r
 \r
+  GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);\r
+  if (ThreadId != 0) {\r
+    //\r
+    // Skip loading microcode if it is not the first thread in one core.\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
+  // GetProcessorCpuid() cannot be used here to retrieve CPUID data.\r
   //\r
   AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);\r
 \r
@@ -91,16 +141,58 @@ MicrocodeDetect (
   PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
   PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
 \r
+  //\r
+  // Check whether AP has same processor with BSP.\r
+  // If yes, direct use microcode info saved by BSP.\r
+  //\r
+  if (!IsBspCallIn) {\r
+    if ((CpuMpData->ProcessorSignature == Eax.Uint32) &&\r
+        (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) {\r
+        MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress;\r
+        LatestRevision = CpuMpData->MicrocodeRevision;\r
+        goto Done;\r
+    }\r
+  }\r
+\r
   LatestRevision = 0;\r
   MicrocodeData  = NULL;\r
-  MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);\r
-  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
+  MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);\r
+  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
+\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
+\r
+    if (MicrocodeEntryPoint->DataSize == 0) {\r
+      TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;\r
+    } else {\r
+      TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;\r
+    }\r
+\r
+    ///\r
+    /// Check overflow and whether TotalSize is aligned with 4 bytes.\r
+    ///\r
+    if ( ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
+         (TotalSize & 0x3) != 0\r
+       ) {\r
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
+    //\r
+    InCompleteCheckSum32 = CalculateSum32 (\r
+                             (UINT32 *) MicrocodeEntryPoint,\r
+                             TotalSize\r
+                             );\r
+    InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+    InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
+    InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
+\r
     if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
       //\r
       // It is the microcode header. It is not the padding data between microcode patches\r
@@ -111,16 +203,16 @@ MicrocodeDetect (
           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
+        //\r
+        // Calculate CheckSum Part1.\r
+        //\r
+        CheckSum32 = InCompleteCheckSum32;\r
+        CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+        CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;\r
+        CheckSum32 += MicrocodeEntryPoint->Checksum;\r
         if (CheckSum32 == 0) {\r
           CorrectMicrocode = TRUE;\r
+          ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;\r
         }\r
       } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
                  (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
@@ -136,6 +228,9 @@ MicrocodeDetect (
           // Calculate Extended Checksum\r
           //\r
           if ((ExtendedTableLength % 4) == 0) {\r
+            //\r
+            // Calculate CheckSum Part2.\r
+            //\r
             CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);\r
             if (CheckSum32 == 0) {\r
               //\r
@@ -144,7 +239,13 @@ MicrocodeDetect (
               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
+                //\r
+                // Calculate CheckSum Part3.\r
+                //\r
+                CheckSum32 = InCompleteCheckSum32;\r
+                CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
+                CheckSum32 += ExtendedTable->ProcessorFlag;\r
+                CheckSum32 += ExtendedTable->Checksum;\r
                 if (CheckSum32 == 0) {\r
                   //\r
                   // Verify Header\r
@@ -155,6 +256,7 @@ MicrocodeDetect (
                     // Find one\r
                     //\r
                     CorrectMicrocode = TRUE;\r
+                    ProcessorFlags = ExtendedTable->ProcessorFlag;\r
                     break;\r
                   }\r
                 }\r
@@ -192,6 +294,7 @@ MicrocodeDetect (
     MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
   } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
 \r
+Done:\r
   if (LatestRevision > CurrentRevision) {\r
     //\r
     // BIOS only authenticate updates that contain a numerically larger revision\r
@@ -215,4 +318,16 @@ MicrocodeDetect (
       ReleaseSpinLock(&CpuMpData->MpLock);\r
     }\r
   }\r
+\r
+  if (IsBspCallIn && (LatestRevision != 0)) {\r
+    //\r
+    // Save BSP processor info and microcode info for later AP use.\r
+    //\r
+    CpuMpData->ProcessorSignature   = Eax.Uint32;\r
+    CpuMpData->ProcessorFlags       = ProcessorFlags;\r
+    CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData;\r
+    CpuMpData->MicrocodeRevision    = LatestRevision;\r
+    DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \\r
+       MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));\r
+  }\r
 }\r