--- /dev/null
+/** @file\r
+ Public include file for Microcode library.\r
+\r
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef MICROCODE_LIB_H_\r
+#define MICROCODE_LIB_H_\r
+\r
+#include <Register/Intel/Microcode.h>\r
+#include <Ppi/ShadowMicrocode.h>\r
+\r
+/**\r
+ Get microcode update signature of currently loaded microcode update.\r
+\r
+ @return Microcode signature.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetProcessorMicrocodeSignature (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Get the processor signature and platform ID for current processor.\r
+\r
+ @param MicrocodeCpuId Return the processor signature and platform ID.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetProcessorMicrocodeCpuId (\r
+ EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId\r
+ );\r
+\r
+/**\r
+ Return the total size of the microcode entry.\r
+\r
+ Logic follows pseudo code in SDM as below:\r
+\r
+ N = 512\r
+ If (Update.DataSize != 00000000H)\r
+ N = Update.TotalSize / 4\r
+\r
+ If Microcode is NULL, then ASSERT.\r
+\r
+ @param Microcode Pointer to the microcode entry.\r
+\r
+ @return The microcode total size.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetMicrocodeLength (\r
+ IN CPU_MICROCODE_HEADER *Microcode\r
+ );\r
+\r
+/**\r
+ Load the microcode to the processor.\r
+\r
+ If Microcode is NULL, then ASSERT.\r
+\r
+ @param Microcode Pointer to the microcode entry.\r
+**/\r
+VOID\r
+EFIAPI\r
+LoadMicrocode (\r
+ IN CPU_MICROCODE_HEADER *Microcode\r
+ );\r
+\r
+/**\r
+ Detect whether specified processor can find matching microcode patch and load it.\r
+\r
+ Microcode format is as below:\r
+ +----------------------------------------+-------------------------------------------------+\r
+ | CPU_MICROCODE_HEADER | |\r
+ +----------------------------------------+ V\r
+ | Update Data | CPU_MICROCODE_HEADER.Checksum\r
+ +----------------------------------------+-------+ ^\r
+ | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | |\r
+ +----------------------------------------+ V |\r
+ | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum |\r
+ | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ |\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
+ If Microcode is NULL, then ASSERT.\r
+\r
+ @param Microcode Pointer to a microcode entry.\r
+ @param MicrocodeLength The total length of the microcode entry.\r
+ @param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid.\r
+ Caller can supply value get from GetProcessorMicrocodeSignature() to check\r
+ whether the microcode is newer than loaded one.\r
+ Caller can supply 0 to treat any revision (except 0) microcode as valid.\r
+ @param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents\r
+ a set of processors.\r
+ Caller can supply zero-element array to skip the processor signature and\r
+ platform ID check.\r
+ @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.\r
+ @param VerifyChecksum FALSE to skip all the checksum verifications.\r
+\r
+ @retval TRUE The microcode is valid.\r
+ @retval FALSE The microcode is invalid.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsValidMicrocode (\r
+ IN CPU_MICROCODE_HEADER *Microcode,\r
+ IN UINTN MicrocodeLength,\r
+ IN UINT32 MinimumRevision,\r
+ IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,\r
+ IN UINTN MicrocodeCpuIdCount,\r
+ IN BOOLEAN VerifyChecksum\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Implementation of MicrocodeLib.\r
+\r
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Register/Intel/Cpuid.h>\r
+#include <Register/Intel/ArchitecturalMsr.h>\r
+#include <Register/Intel/Microcode.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Ppi/ShadowMicrocode.h>\r
+\r
+/**\r
+ Get microcode update signature of currently loaded microcode update.\r
+\r
+ @return Microcode signature.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetProcessorMicrocodeSignature (\r
+ VOID\r
+ )\r
+{\r
+ MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;\r
+\r
+ AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);\r
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
+ BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);\r
+ return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;\r
+}\r
+\r
+/**\r
+ Get the processor signature and platform ID for current processor.\r
+\r
+ @param MicrocodeCpuId Return the processor signature and platform ID.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetProcessorMicrocodeCpuId (\r
+ EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId\r
+ )\r
+{\r
+ MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;\r
+\r
+ ASSERT (MicrocodeCpuId != NULL);\r
+\r
+ PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
+ MicrocodeCpuId->PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
+ AsmCpuid (CPUID_VERSION_INFO, &MicrocodeCpuId->ProcessorSignature, NULL, NULL, NULL);\r
+}\r
+\r
+/**\r
+ Return the total size of the microcode entry.\r
+\r
+ Logic follows pseudo code in SDM as below:\r
+\r
+ N = 512\r
+ If (Update.DataSize != 00000000H)\r
+ N = Update.TotalSize / 4\r
+\r
+ If Microcode is NULL, then ASSERT.\r
+\r
+ @param Microcode Pointer to the microcode entry.\r
+\r
+ @return The microcode total size.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetMicrocodeLength (\r
+ IN CPU_MICROCODE_HEADER *Microcode\r
+ )\r
+{\r
+ UINT32 TotalSize;\r
+\r
+ ASSERT (Microcode != NULL);\r
+\r
+ TotalSize = 2048;\r
+ if (Microcode->DataSize != 0) {\r
+ TotalSize = Microcode->TotalSize;\r
+ }\r
+ return TotalSize;\r
+}\r
+\r
+/**\r
+ Load the microcode to the processor.\r
+\r
+ If Microcode is NULL, then ASSERT.\r
+\r
+ @param Microcode Pointer to the microcode entry.\r
+**/\r
+VOID\r
+EFIAPI\r
+LoadMicrocode (\r
+ IN CPU_MICROCODE_HEADER *Microcode\r
+ )\r
+{\r
+ ASSERT (Microcode != NULL);\r
+\r
+ AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG, (UINT64) (UINTN) (Microcode + 1));\r
+}\r
+\r
+/**\r
+ Determine if a microcode patch matchs the specific processor signature and flag.\r
+\r
+ @param[in] ProcessorSignature The processor signature field value in a\r
+ microcode patch.\r
+ @param[in] ProcessorFlags The processor flags field value in a\r
+ microcode patch.\r
+ @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID\r
+ structures.\r
+ @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array.\r
+\r
+ @retval TRUE The specified microcode patch matches to one of the MicrocodeCpuId.\r
+ @retval FALSE The specified microcode patch doesn't match to any of the MicrocodeCpuId.\r
+**/\r
+BOOLEAN\r
+IsProcessorMatchedMicrocode (\r
+ IN UINT32 ProcessorSignature,\r
+ IN UINT32 ProcessorFlags,\r
+ IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId,\r
+ IN UINTN MicrocodeCpuIdCount\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ if (MicrocodeCpuIdCount == 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ for (Index = 0; Index < MicrocodeCpuIdCount; Index++) {\r
+ if ((ProcessorSignature == MicrocodeCpuId[Index].ProcessorSignature) &&\r
+ (ProcessorFlags & (1 << MicrocodeCpuId[Index].PlatformId)) != 0) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Detect whether specified processor can find matching microcode patch and load it.\r
+\r
+ Microcode format is as below:\r
+ +----------------------------------------+-------------------------------------------------+\r
+ | CPU_MICROCODE_HEADER | |\r
+ +----------------------------------------+ V\r
+ | Update Data | CPU_MICROCODE_HEADER.Checksum\r
+ +----------------------------------------+-------+ ^\r
+ | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | |\r
+ +----------------------------------------+ V |\r
+ | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum |\r
+ | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ |\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
+ If Microcode is NULL, then ASSERT.\r
+\r
+ @param Microcode Pointer to a microcode entry.\r
+ @param MicrocodeLength The total length of the microcode entry.\r
+ @param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid.\r
+ Caller can supply value get from GetProcessorMicrocodeSignature() to check\r
+ whether the microcode is newer than loaded one.\r
+ Caller can supply 0 to treat any revision (except 0) microcode as valid.\r
+ @param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents\r
+ a set of processors.\r
+ Caller can supply zero-element array to skip the processor signature and\r
+ platform ID check.\r
+ @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.\r
+ @param VerifyChecksum FALSE to skip all the checksum verifications.\r
+\r
+ @retval TRUE The microcode is valid.\r
+ @retval FALSE The microcode is invalid.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsValidMicrocode (\r
+ IN CPU_MICROCODE_HEADER *Microcode,\r
+ IN UINTN MicrocodeLength,\r
+ IN UINT32 MinimumRevision,\r
+ IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,\r
+ IN UINTN MicrocodeCpuIdCount,\r
+ IN BOOLEAN VerifyChecksum\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 DataSize;\r
+ UINT32 TotalSize;\r
+ CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
+ CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
+ UINT32 ExtendedTableLength;\r
+ UINT32 Sum32;\r
+ BOOLEAN Match;\r
+\r
+ ASSERT (Microcode != NULL);\r
+\r
+ //\r
+ // It's invalid when:\r
+ // the input microcode buffer is so small that even cannot contain the header.\r
+ // the input microcode buffer is so large that exceeds MAX_ADDRESS.\r
+ //\r
+ if ((MicrocodeLength < sizeof (CPU_MICROCODE_HEADER)) || (MicrocodeLength > (MAX_ADDRESS - (UINTN) Microcode))) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Per SDM, HeaderVersion and LoaderRevision should both be 1.\r
+ //\r
+ if ((Microcode->HeaderVersion != 1) || (Microcode->LoaderRevision != 1)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // The microcode revision should be larger than the minimum revision.\r
+ //\r
+ if (Microcode->UpdateRevision <= MinimumRevision) {\r
+ return FALSE;\r
+ }\r
+\r
+ DataSize = Microcode->DataSize;\r
+ if (DataSize == 0) {\r
+ DataSize = 2000;\r
+ }\r
+\r
+ //\r
+ // Per SDM, DataSize should be multiple of DWORDs.\r
+ //\r
+ if ((DataSize % 4) != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ TotalSize = GetMicrocodeLength (Microcode);\r
+\r
+ //\r
+ // Check whether the whole microcode is within the buffer.\r
+ // TotalSize should be multiple of 1024.\r
+ //\r
+ if (((TotalSize % SIZE_1KB) != 0) || (TotalSize > MicrocodeLength)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // The summation of all DWORDs in microcode should be zero.\r
+ //\r
+ if (VerifyChecksum && (CalculateSum32 ((UINT32 *) Microcode, TotalSize) != 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Sum32 = Microcode->ProcessorSignature.Uint32 + Microcode->ProcessorFlags + Microcode->Checksum;\r
+\r
+ //\r
+ // Check the processor signature and platform ID in the primary header.\r
+ //\r
+ Match = IsProcessorMatchedMicrocode (\r
+ Microcode->ProcessorSignature.Uint32,\r
+ Microcode->ProcessorFlags,\r
+ MicrocodeCpuIds,\r
+ MicrocodeCpuIdCount\r
+ );\r
+ if (Match) {\r
+ return TRUE;\r
+ }\r
+\r
+ ExtendedTableLength = TotalSize - (DataSize + sizeof (CPU_MICROCODE_HEADER));\r
+ if ((ExtendedTableLength < sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) || ((ExtendedTableLength % 4) != 0)) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Extended Table exist, check if the CPU in support list\r
+ //\r
+ ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINTN) (Microcode + 1) + DataSize);\r
+ if (ExtendedTableHeader->ExtendedSignatureCount > MAX_UINT32 / sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {\r
+ return FALSE;\r
+ }\r
+ if (ExtendedTableHeader->ExtendedSignatureCount * sizeof (CPU_MICROCODE_EXTENDED_TABLE)\r
+ > ExtendedTableLength - sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Check the extended table checksum\r
+ //\r
+ if (VerifyChecksum && (CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength) != 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
+ for (Index = 0; Index < ExtendedTableHeader->ExtendedSignatureCount; Index ++) {\r
+ if (VerifyChecksum &&\r
+ (ExtendedTable[Index].ProcessorSignature.Uint32 + ExtendedTable[Index].ProcessorFlag\r
+ + ExtendedTable[Index].Checksum != Sum32)) {\r
+ //\r
+ // The extended table entry is valid when the summation of Processor Signature, Processor Flags\r
+ // and Checksum equal to the coresponding summation from primary header. Because:\r
+ // CalculateSum32 (Header + Update Binary) == 0\r
+ // CalculateSum32 (Header + Update Binary)\r
+ // - (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)\r
+ // + (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum) == 0\r
+ // So,\r
+ // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)\r
+ // == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum)\r
+ //\r
+ continue;\r
+ }\r
+ Match = IsProcessorMatchedMicrocode (\r
+ ExtendedTable[Index].ProcessorSignature.Uint32,\r
+ ExtendedTable[Index].ProcessorFlag,\r
+ MicrocodeCpuIds,\r
+ MicrocodeCpuIdCount\r
+ );\r
+ if (Match) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r