]> 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 e47f9f4f8f349b2fbc94c1a1f138c19be1653a40..643a6f94f4a5fb1d0aee99f1da954bf12f8f96be 100644 (file)
@@ -35,11 +35,49 @@ GetCurrentMicrocodeSignature (
 /**\r
   Detect whether specified processor can find matching microcode patch and load it.\r
 \r
-  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\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
   UINT32                                  ExtendedTableLength;\r
@@ -55,9 +93,17 @@ 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
+  //\r
+  // set ProcessorFlags to suppress incorrect compiler/analyzer warnings\r
+  //\r
+  ProcessorFlags = 0;\r
 \r
   if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
     //\r
@@ -67,13 +113,21 @@ 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
@@ -87,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) (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
@@ -107,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
@@ -132,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
@@ -140,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
@@ -151,6 +256,7 @@ MicrocodeDetect (
                     // Find one\r
                     //\r
                     CorrectMicrocode = TRUE;\r
+                    ProcessorFlags = ExtendedTable->ProcessorFlag;\r
                     break;\r
                   }\r
                 }\r
@@ -188,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
@@ -211,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