diff --git a/UefiCpuPkg/Include/Ppi/ShadowMicrocode.h b/UefiCpuPkg/Include/Ppi/ShadowMicrocode.h new file mode 100644 index 0000000000..be48965422 --- /dev/null +++ b/UefiCpuPkg/Include/Ppi/ShadowMicrocode.h @@ -0,0 +1,66 @@ +/** @file + This file declares EDKII Shadow Microcode PPI. + + Copyright (c) 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PPI_SHADOW_MICROCODE_H__ +#define __PPI_SHADOW_MICROCODE_H__ + +#define EDKII_PEI_SHADOW_MICROCODE_PPI_GUID \ + { \ + 0x430f6965, 0x9a69, 0x41c5, { 0x93, 0xed, 0x8b, 0xf0, 0x64, 0x35, 0xc1, 0xc6 } \ + } + +typedef struct _EDKII_PEI_SHADOW_MICROCODE_PPI EDKII_PEI_SHADOW_MICROCODE_PPI; + +typedef struct { + UINT32 ProcessorSignature; + UINT8 PlatformId; +} EDKII_PEI_MICROCODE_CPU_ID; + +/** + Shadow microcode update patches to memory. + + The function is used for shadowing microcode update patches to a continuous memory. + It shall allocate memory buffer and only shadow the microcode patches for those + processors specified by MicrocodeCpuId array. The checksum verification may be + skiped in this function so the caller must perform checksum verification before + using the microcode patches in returned memory buffer. + + @param[in] This The PPI instance pointer. + @param[in] CpuIdCount Number of elements in MicrocodeCpuId array. + @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID + structures. + @param[out] BufferSize Pointer to receive the total size of Buffer. + @param[out] Buffer Pointer to receive address of allocated memory + with microcode patches data in it. + + @retval EFI_SUCCESS The microcode has been shadowed to memory. + @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_PEI_SHADOW_MICROCODE) ( + IN EDKII_PEI_SHADOW_MICROCODE_PPI *This, + IN UINTN CpuIdCount, + IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId, + OUT UINTN *BufferSize, + OUT VOID **Buffer + ); + +/// +/// This PPI is installed by some platform or chipset-specific PEIM that +/// abstracts handling microcode shadow support. +/// +struct _EDKII_PEI_SHADOW_MICROCODE_PPI { + EDKII_PEI_SHADOW_MICROCODE ShadowMicrocode; +}; + +extern EFI_GUID gEdkiiPeiShadowMicrocodePpiGuid; + +#endif + diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf index 9e6cce0895..45aaa179ff 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -69,6 +69,5 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES - gUefiCpuPkgTokenSpaceGuid.PcdCpuShadowMicrocodeByFit ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c index b17e287bbf..a987c32109 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c @@ -1,7 +1,7 @@ /** @file MP initialize support functions for DXE phase. - Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -816,3 +816,27 @@ MpInitLibEnableDisableAP ( return Status; } + +/** + This funtion will try to invoke platform specific microcode shadow logic to + relocate microcode update patches into memory. + + @param[in] CpuMpData The pointer to CPU MP Data structure. + + @retval EFI_SUCCESS Shadow microcode success. + @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation. + @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow + PPI/Protocol. +**/ +EFI_STATUS +PlatformShadowMicrocode ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + // + // There is no DXE version of platform shadow microcode protocol so far. + // A platform which only uses DxeMpInitLib instance could only supports + // the PCD based microcode shadowing. + // + return EFI_UNSUPPORTED; +} diff --git a/UefiCpuPkg/Library/MpInitLib/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c index 67e214d463..15629591e2 100644 --- a/UefiCpuPkg/Library/MpInitLib/Microcode.c +++ b/UefiCpuPkg/Library/MpInitLib/Microcode.c @@ -619,109 +619,6 @@ OnExit: return; } -/** - Shadow the required microcode patches data into memory according to FIT microcode entry. - - @param[in, out] CpuMpData The pointer to CPU MP Data structure. - - @return EFI_SUCCESS Microcode patch is shadowed into memory. - @return EFI_UNSUPPORTED FIT based microcode shadowing is not supported. - @return EFI_OUT_OF_RESOURCES No enough memory resource. - @return EFI_NOT_FOUND There is something wrong in FIT microcode entry. - -**/ -EFI_STATUS -ShadowMicrocodePatchByFit ( - IN OUT CPU_MP_DATA *CpuMpData - ) -{ - UINT64 FitPointer; - FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry; - UINT32 EntryNum; - UINT32 Index; - MICROCODE_PATCH_INFO *PatchInfoBuffer; - UINTN MaxPatchNumber; - CPU_MICROCODE_HEADER *MicrocodeEntryPoint; - UINTN PatchCount; - UINTN TotalSize; - UINTN TotalLoadSize; - - if (!FeaturePcdGet (PcdCpuShadowMicrocodeByFit)) { - return EFI_UNSUPPORTED; - } - - FitPointer = *(UINT64 *) (UINTN) FIT_POINTER_ADDRESS; - if ((FitPointer == 0) || - (FitPointer == 0xFFFFFFFFFFFFFFFF) || - (FitPointer == 0xEEEEEEEEEEEEEEEE)) { - // - // No FIT table. - // - ASSERT (FALSE); - return EFI_NOT_FOUND; - } - FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *) (UINTN) FitPointer; - if ((FitEntry[0].Type != FIT_TYPE_00_HEADER) || - (FitEntry[0].Address != FIT_TYPE_00_SIGNATURE)) { - // - // Invalid FIT table, treat it as no FIT table. - // - ASSERT (FALSE); - return EFI_NOT_FOUND; - } - - EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF; - - // - // Calculate microcode entry number - // - MaxPatchNumber = 0; - for (Index = 0; Index < EntryNum; Index++) { - if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) { - MaxPatchNumber++; - } - } - if (MaxPatchNumber == 0) { - return EFI_NOT_FOUND; - } - - PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO)); - if (PatchInfoBuffer == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - // - // Fill up microcode patch info buffer according to FIT table. - // - PatchCount = 0; - TotalLoadSize = 0; - for (Index = 0; Index < EntryNum; Index++) { - if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) { - MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) FitEntry[Index].Address; - TotalSize = (MicrocodeEntryPoint->DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize; - if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) { - PatchInfoBuffer[PatchCount].Address = (UINTN) MicrocodeEntryPoint; - PatchInfoBuffer[PatchCount].Size = TotalSize; - TotalLoadSize += TotalSize; - PatchCount++; - } - } - } - - 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); - } - - FreePool (PatchInfoBuffer); - return EFI_SUCCESS; -} - /** Shadow the required microcode patches data into memory. @@ -734,7 +631,7 @@ ShadowMicrocodeUpdatePatch ( { EFI_STATUS Status; - Status = ShadowMicrocodePatchByFit (CpuMpData); + Status = PlatformShadowMicrocode (CpuMpData); if (EFI_ERROR (Status)) { ShadowMicrocodePatchByPcd (CpuMpData); } diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index a6eab5f3d7..455cb3f09a 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -31,9 +31,6 @@ #include -#include - - #define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') #define CPU_INIT_MP_LIB_HOB_GUID \ @@ -657,5 +654,21 @@ GetProcessorNumber ( OUT UINTN *ProcessorNumber ); +/** + This funtion will try to invoke platform specific microcode shadow logic to + relocate microcode update patches into memory. + + @param[in] CpuMpData The pointer to CPU MP Data structure. + + @retval EFI_SUCCESS Shadow microcode success. + @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation. + @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow + PPI/Protocol. +**/ +EFI_STATUS +PlatformShadowMicrocode ( + IN OUT CPU_MP_DATA *CpuMpData + ); + #endif diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf index 555125a7c5..d78d328b42 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf @@ -60,7 +60,9 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES - gUefiCpuPkgTokenSpaceGuid.PcdCpuShadowMicrocodeByFit ## CONSUMES + +[Ppis] + gEdkiiPeiShadowMicrocodePpiGuid ## SOMETIMES_CONSUMES [Guids] gEdkiiS3SmmInitDoneGuid diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c index 6ecbed39ec..17b60903c5 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c @@ -9,6 +9,7 @@ #include "MpLib.h" #include #include +#include /** S3 SMM Init Done notification function. @@ -639,4 +640,71 @@ MpInitLibEnableDisableAP ( return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag); } +/** + This funtion will try to invoke platform specific microcode shadow logic to + relocate microcode update patches into memory. + @param[in] CpuMpData The pointer to CPU MP Data structure. + + @retval EFI_SUCCESS Shadow microcode success. + @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation. + @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow + PPI/Protocol. +**/ +EFI_STATUS +PlatformShadowMicrocode ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + EFI_STATUS Status; + EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi; + UINTN CpuCount; + EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId; + UINTN Index; + UINTN BufferSize; + VOID *Buffer; + + Status = PeiServicesLocatePpi ( + &gEdkiiPeiShadowMicrocodePpiGuid, + 0, + NULL, + (VOID **) &ShadowMicrocodePpi + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + CpuCount = CpuMpData->CpuCount; + MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *) AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount); + if (MicrocodeCpuId == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature; + MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId; + } + + Status = ShadowMicrocodePpi->ShadowMicrocode ( + ShadowMicrocodePpi, + CpuCount, + MicrocodeCpuId, + &BufferSize, + &Buffer + ); + FreePool (MicrocodeCpuId); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + CpuMpData->MicrocodePatchAddress = (UINTN) Buffer; + CpuMpData->MicrocodePatchRegionSize = BufferSize; + + DEBUG (( + DEBUG_INFO, + "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n", + __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize + )); + + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index a6ebdde1cf..e91dc68cbe 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -1,7 +1,7 @@ ## @file UefiCpuPkg.dec # This Package provides UEFI compatible CPU modules and libraries. # -# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -81,6 +81,9 @@ [Ppis] gEdkiiPeiMpServices2PpiGuid = { 0x5cb9cb3d, 0x31a4, 0x480c, { 0x94, 0x98, 0x29, 0xd2, 0x69, 0xba, 0xcf, 0xba}} + ## Include/Ppi/ShadowMicrocode.h + gEdkiiPeiShadowMicrocodePpiGuid = { 0x430f6965, 0x9a69, 0x41c5, { 0x93, 0xed, 0x8b, 0xf0, 0x64, 0x35, 0xc1, 0xc6 }} + [PcdsFeatureFlag] ## Indicates if SMM Profile will be enabled. # If enabled, instruction executions in and data accesses to memory outside of SMRAM will be logged. @@ -139,12 +142,6 @@ # @Prompt Lock SMM Feature Control MSR. gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock|TRUE|BOOLEAN|0x3213210B - ## Indicates if FIT based microcode shadowing will be enabled.

- # TRUE - FIT base microcode shadowing will be enabled.
- # FALSE - FIT base microcode shadowing will be disabled.
- # @Prompt FIT based microcode shadowing. - gUefiCpuPkgTokenSpaceGuid.PcdCpuShadowMicrocodeByFit|FALSE|BOOLEAN|0x3213210D - [PcdsFixedAtBuild] ## List of exception vectors which need switching stack. # This PCD will only take into effect if PcdCpuStackGuard is enabled. diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni index 2db49e841b..c0d6ed5136 100644 --- a/UefiCpuPkg/UefiCpuPkg.uni +++ b/UefiCpuPkg/UefiCpuPkg.uni @@ -100,12 +100,6 @@ "TRUE - locked.
\n" "FALSE - unlocked.
" -#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuShadowMicrocodeByFit_PROMPT #language en-US "FIT based microcode shadowing" - -#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuShadowMicrocodeByFit_HELP #language en-US "Indicates if FIT based microcode shadowing will be enabled.

\n" - "TRUE - FIT base microcode shadowing will be enabled.
\n" - "FALSE - FIT base microcode shadowing will be disabled.
" - #string STR_gUefiCpuPkgTokenSpaceGuid_PcdPeiTemporaryRamStackSize_PROMPT #language en-US "Stack size in the temporary RAM" #string STR_gUefiCpuPkgTokenSpaceGuid_PcdPeiTemporaryRamStackSize_HELP #language en-US "Specifies stack size in the temporary RAM. 0 means half of TemporaryRamSize."