REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the UefiCpuPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			387 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			387 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Implementation of loading microcode on processors.
 | |
| 
 | |
|   Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "MpLib.h"
 | |
| 
 | |
| /**
 | |
|   Detect whether specified processor can find matching microcode patch and load it.
 | |
| 
 | |
|   @param[in]  CpuMpData        The pointer to CPU MP Data structure.
 | |
|   @param[in]  ProcessorNumber  The handle number of the processor. The range is
 | |
|                                from 0 to the total number of logical processors
 | |
|                                minus 1.
 | |
| **/
 | |
| VOID
 | |
| MicrocodeDetect (
 | |
|   IN CPU_MP_DATA  *CpuMpData,
 | |
|   IN UINTN        ProcessorNumber
 | |
|   )
 | |
| {
 | |
|   CPU_MICROCODE_HEADER        *Microcode;
 | |
|   UINTN                       MicrocodeEnd;
 | |
|   CPU_AP_DATA                 *BspData;
 | |
|   UINT32                      LatestRevision;
 | |
|   CPU_MICROCODE_HEADER        *LatestMicrocode;
 | |
|   UINT32                      ThreadId;
 | |
|   EDKII_PEI_MICROCODE_CPU_ID  MicrocodeCpuId;
 | |
| 
 | |
|   if (CpuMpData->MicrocodePatchRegionSize == 0) {
 | |
|     //
 | |
|     // There is no microcode patches
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
 | |
|   if (ThreadId != 0) {
 | |
|     //
 | |
|     // Skip loading microcode if it is not the first thread in one core.
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   GetProcessorMicrocodeCpuId (&MicrocodeCpuId);
 | |
| 
 | |
|   if (ProcessorNumber != (UINTN)CpuMpData->BspNumber) {
 | |
|     //
 | |
|     // Direct use microcode of BSP if AP is the same as BSP.
 | |
|     // Assume BSP calls this routine() before AP.
 | |
|     //
 | |
|     BspData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
 | |
|     if ((BspData->ProcessorSignature == MicrocodeCpuId.ProcessorSignature) &&
 | |
|         (BspData->PlatformId == MicrocodeCpuId.PlatformId) &&
 | |
|         (BspData->MicrocodeEntryAddr != 0))
 | |
|     {
 | |
|       LatestMicrocode = (CPU_MICROCODE_HEADER *)(UINTN)BspData->MicrocodeEntryAddr;
 | |
|       LatestRevision  = LatestMicrocode->UpdateRevision;
 | |
|       goto LoadMicrocode;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // BSP or AP which is different from BSP runs here
 | |
|   // Use 0 as the starting revision to search for microcode because MicrocodePatchInfo HOB needs
 | |
|   // the latest microcode location even it's loaded to the processor.
 | |
|   //
 | |
|   LatestRevision  = 0;
 | |
|   LatestMicrocode = NULL;
 | |
|   Microcode       = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;
 | |
|   MicrocodeEnd    = (UINTN)Microcode + (UINTN)CpuMpData->MicrocodePatchRegionSize;
 | |
| 
 | |
|   do {
 | |
|     if (!IsValidMicrocode (Microcode, MicrocodeEnd - (UINTN)Microcode, LatestRevision, &MicrocodeCpuId, 1, TRUE)) {
 | |
|       //
 | |
|       // 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.
 | |
|       //
 | |
|       Microcode = (CPU_MICROCODE_HEADER *)((UINTN)Microcode + SIZE_1KB);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     LatestMicrocode = Microcode;
 | |
|     LatestRevision  = LatestMicrocode->UpdateRevision;
 | |
| 
 | |
|     Microcode = (CPU_MICROCODE_HEADER *)(((UINTN)Microcode) + GetMicrocodeLength (Microcode));
 | |
|   } while ((UINTN)Microcode < MicrocodeEnd);
 | |
| 
 | |
| LoadMicrocode:
 | |
|   if (LatestRevision != 0) {
 | |
|     //
 | |
|     // Save the detected microcode patch entry address (including the microcode
 | |
|     // patch header) for each processor even it's the same as the loaded one.
 | |
|     // It will be used when building the microcode patch cache HOB.
 | |
|     //
 | |
|     CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN)LatestMicrocode;
 | |
|   }
 | |
| 
 | |
|   if (LatestRevision > GetProcessorMicrocodeSignature ()) {
 | |
|     //
 | |
|     // BIOS only authenticate updates that contain a numerically larger revision
 | |
|     // than the currently loaded revision, where Current Signature < New Update
 | |
|     // Revision. A processor with no loaded update is considered to have a
 | |
|     // revision equal to zero.
 | |
|     //
 | |
|     LoadMicrocode (LatestMicrocode);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.
 | |
|   //
 | |
|   CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Actual worker function that shadows the required microcode patches into memory.
 | |
| 
 | |
|   @param[in, out]  CpuMpData        The pointer to CPU MP Data structure.
 | |
|   @param[in]       Patches          The pointer to an array of information on
 | |
|                                     the microcode patches that will be loaded
 | |
|                                     into memory.
 | |
|   @param[in]       PatchCount       The number of microcode patches that will
 | |
|                                     be loaded into memory.
 | |
|   @param[in]       TotalLoadSize    The total size of all the microcode patches
 | |
|                                     to be loaded.
 | |
| **/
 | |
| VOID
 | |
| ShadowMicrocodePatchWorker (
 | |
|   IN OUT CPU_MP_DATA           *CpuMpData,
 | |
|   IN     MICROCODE_PATCH_INFO  *Patches,
 | |
|   IN     UINTN                 PatchCount,
 | |
|   IN     UINTN                 TotalLoadSize
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
|   VOID   *MicrocodePatchInRam;
 | |
|   UINT8  *Walker;
 | |
| 
 | |
|   ASSERT ((Patches != NULL) && (PatchCount != 0));
 | |
| 
 | |
|   MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
 | |
|   if (MicrocodePatchInRam == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Load all the required microcode patches into memory
 | |
|   //
 | |
|   for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
 | |
|     CopyMem (
 | |
|       Walker,
 | |
|       (VOID *)Patches[Index].Address,
 | |
|       Patches[Index].Size
 | |
|       );
 | |
|     Walker += Patches[Index].Size;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update the microcode patch related fields in CpuMpData
 | |
|   //
 | |
|   CpuMpData->MicrocodePatchAddress    = (UINTN)MicrocodePatchInRam;
 | |
|   CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_INFO,
 | |
|     "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
 | |
|     __FUNCTION__,
 | |
|     CpuMpData->MicrocodePatchAddress,
 | |
|     CpuMpData->MicrocodePatchRegionSize
 | |
|     ));
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Shadow the required microcode patches data into memory according to PCD
 | |
|   PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.
 | |
| 
 | |
|   @param[in, out]  CpuMpData    The pointer to CPU MP Data structure.
 | |
| **/
 | |
| VOID
 | |
| ShadowMicrocodePatchByPcd (
 | |
|   IN OUT CPU_MP_DATA  *CpuMpData
 | |
|   )
 | |
| {
 | |
|   UINTN                       Index;
 | |
|   CPU_MICROCODE_HEADER        *MicrocodeEntryPoint;
 | |
|   UINTN                       MicrocodeEnd;
 | |
|   UINTN                       TotalSize;
 | |
|   MICROCODE_PATCH_INFO        *PatchInfoBuffer;
 | |
|   UINTN                       MaxPatchNumber;
 | |
|   UINTN                       PatchCount;
 | |
|   UINTN                       TotalLoadSize;
 | |
|   EDKII_PEI_MICROCODE_CPU_ID  *MicrocodeCpuIds;
 | |
|   BOOLEAN                     Valid;
 | |
| 
 | |
|   //
 | |
|   // Initialize the microcode patch related fields in CpuMpData as the values
 | |
|   // specified by the PCD pair. If the microcode patches are loaded into memory,
 | |
|   // these fields will be updated.
 | |
|   //
 | |
|   CpuMpData->MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);
 | |
|   CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
 | |
| 
 | |
|   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;
 | |
|   MicrocodeEnd        = (UINTN)MicrocodeEntryPoint +
 | |
|                         (UINTN)CpuMpData->MicrocodePatchRegionSize;
 | |
|   if ((MicrocodeEntryPoint == NULL) || ((UINTN)MicrocodeEntryPoint == MicrocodeEnd)) {
 | |
|     //
 | |
|     // There is no microcode patches
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   PatchCount      = 0;
 | |
|   MaxPatchNumber  = DEFAULT_MAX_MICROCODE_PATCH_NUM;
 | |
|   TotalLoadSize   = 0;
 | |
|   PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
 | |
|   if (PatchInfoBuffer == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   MicrocodeCpuIds = AllocatePages (
 | |
|                       EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID))
 | |
|                       );
 | |
|   if (MicrocodeCpuIds == NULL) {
 | |
|     FreePool (PatchInfoBuffer);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
 | |
|     MicrocodeCpuIds[Index].PlatformId         = CpuMpData->CpuData[Index].PlatformId;
 | |
|     MicrocodeCpuIds[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Process the header of each microcode patch within the region.
 | |
|   // The purpose is to decide which microcode patch(es) will be loaded into memory.
 | |
|   // Microcode checksum is not verified because it's slow when performing on flash.
 | |
|   //
 | |
|   do {
 | |
|     Valid = IsValidMicrocode (
 | |
|               MicrocodeEntryPoint,
 | |
|               MicrocodeEnd - (UINTN)MicrocodeEntryPoint,
 | |
|               0,
 | |
|               MicrocodeCpuIds,
 | |
|               CpuMpData->CpuCount,
 | |
|               FALSE
 | |
|               );
 | |
|     if (!Valid) {
 | |
|       //
 | |
|       // Padding data between the microcode patches, skip 1KB to check next entry.
 | |
|       //
 | |
|       MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     PatchCount++;
 | |
|     if (PatchCount > MaxPatchNumber) {
 | |
|       //
 | |
|       // Current 'PatchInfoBuffer' cannot hold the information, double the size
 | |
|       // and allocate a new buffer.
 | |
|       //
 | |
|       if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
 | |
|         //
 | |
|         // Overflow check for MaxPatchNumber
 | |
|         //
 | |
|         goto OnExit;
 | |
|       }
 | |
| 
 | |
|       PatchInfoBuffer = ReallocatePool (
 | |
|                           MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
 | |
|                           2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
 | |
|                           PatchInfoBuffer
 | |
|                           );
 | |
|       if (PatchInfoBuffer == NULL) {
 | |
|         goto OnExit;
 | |
|       }
 | |
| 
 | |
|       MaxPatchNumber = MaxPatchNumber * 2;
 | |
|     }
 | |
| 
 | |
|     TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);
 | |
| 
 | |
|     //
 | |
|     // Store the information of this microcode patch
 | |
|     //
 | |
|     PatchInfoBuffer[PatchCount - 1].Address = (UINTN)MicrocodeEntryPoint;
 | |
|     PatchInfoBuffer[PatchCount - 1].Size    = TotalSize;
 | |
|     TotalLoadSize                          += TotalSize;
 | |
| 
 | |
|     //
 | |
|     // Process the next microcode patch
 | |
|     //
 | |
|     MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)((UINTN)MicrocodeEntryPoint + TotalSize);
 | |
|   } while ((UINTN)MicrocodeEntryPoint < MicrocodeEnd);
 | |
| 
 | |
|   if (PatchCount != 0) {
 | |
|     DEBUG ((
 | |
|       DEBUG_INFO,
 | |
|       "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
 | |
|       __FUNCTION__,
 | |
|       PatchCount,
 | |
|       TotalLoadSize
 | |
|       ));
 | |
| 
 | |
|     ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
 | |
|   }
 | |
| 
 | |
| OnExit:
 | |
|   if (PatchInfoBuffer != NULL) {
 | |
|     FreePool (PatchInfoBuffer);
 | |
|   }
 | |
| 
 | |
|   FreePages (MicrocodeCpuIds, EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID)));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Shadow the required microcode patches data into memory.
 | |
| 
 | |
|   @param[in, out]  CpuMpData    The pointer to CPU MP Data structure.
 | |
| **/
 | |
| VOID
 | |
| ShadowMicrocodeUpdatePatch (
 | |
|   IN OUT CPU_MP_DATA  *CpuMpData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Status = PlatformShadowMicrocode (CpuMpData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ShadowMicrocodePatchByPcd (CpuMpData);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the cached microcode patch base address and size from the microcode patch
 | |
|   information cache HOB.
 | |
| 
 | |
|   @param[out] Address       Base address of the microcode patches data.
 | |
|                             It will be updated if the microcode patch
 | |
|                             information cache HOB is found.
 | |
|   @param[out] RegionSize    Size of the microcode patches data.
 | |
|                             It will be updated if the microcode patch
 | |
|                             information cache HOB is found.
 | |
| 
 | |
|   @retval  TRUE     The microcode patch information cache HOB is found.
 | |
|   @retval  FALSE    The microcode patch information cache HOB is not found.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| GetMicrocodePatchInfoFromHob (
 | |
|   UINT64  *Address,
 | |
|   UINT64  *RegionSize
 | |
|   )
 | |
| {
 | |
|   EFI_HOB_GUID_TYPE          *GuidHob;
 | |
|   EDKII_MICROCODE_PATCH_HOB  *MicrocodePathHob;
 | |
| 
 | |
|   GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);
 | |
|   if (GuidHob == NULL) {
 | |
|     DEBUG ((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);
 | |
| 
 | |
|   *Address    = MicrocodePathHob->MicrocodePatchAddress;
 | |
|   *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_INFO,
 | |
|     "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",
 | |
|     __FUNCTION__,
 | |
|     *Address,
 | |
|     *RegionSize
 | |
|     ));
 | |
| 
 | |
|   return TRUE;
 | |
| }
 |