2 Implementation of loading microcode on processors.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Get microcode update signature of currently loaded microcode update.
20 @return Microcode signature.
23 GetCurrentMicrocodeSignature (
27 MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr
;
29 AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID
, 0);
30 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, NULL
);
31 BiosSignIdMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID
);
32 return BiosSignIdMsr
.Bits
.MicrocodeUpdateSignature
;
36 Detect whether specified processor can find matching microcode patch and load it.
38 @param[in] CpuMpData The pointer to CPU MP Data structure.
39 @param[in] IsBspCallIn Indicate whether the caller is BSP or not.
43 IN CPU_MP_DATA
*CpuMpData
,
44 IN BOOLEAN IsBspCallIn
47 UINT32 ExtendedTableLength
;
48 UINT32 ExtendedTableCount
;
49 CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
50 CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
51 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
55 CPUID_VERSION_INFO_EAX Eax
;
56 UINT32 CurrentRevision
;
57 UINT32 LatestRevision
;
60 BOOLEAN CorrectMicrocode
;
62 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr
;
63 UINT32 ProcessorFlags
;
67 // set ProcessorFlags to suppress incorrect compiler/analyzer warnings
71 if (CpuMpData
->MicrocodePatchRegionSize
== 0) {
73 // There is no microcode patches
78 CurrentRevision
= GetCurrentMicrocodeSignature ();
79 if (CurrentRevision
!= 0 && !IsBspCallIn
) {
81 // Skip loading microcode if it has been loaded successfully
86 GetProcessorLocationByApicId (GetInitialApicId (), NULL
, NULL
, &ThreadId
);
89 // Skip loading microcode if it is not the first thread in one core.
94 ExtendedTableLength
= 0;
96 // Here data of CPUID leafs have not been collected into context buffer, so
97 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
99 AsmCpuid (CPUID_VERSION_INFO
, &Eax
.Uint32
, NULL
, NULL
, NULL
);
102 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
104 PlatformIdMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_PLATFORM_ID
);
105 PlatformId
= (UINT8
) PlatformIdMsr
.Bits
.PlatformId
;
108 // Check whether AP has same processor with BSP.
109 // If yes, direct use microcode info saved by BSP.
112 if ((CpuMpData
->ProcessorSignature
== Eax
.Uint32
) &&
113 (CpuMpData
->ProcessorFlags
& (1 << PlatformId
)) != 0) {
114 MicrocodeData
= (VOID
*)(UINTN
) CpuMpData
->MicrocodeDataAddress
;
115 LatestRevision
= CpuMpData
->MicrocodeRevision
;
121 MicrocodeData
= NULL
;
122 MicrocodeEnd
= (UINTN
) (CpuMpData
->MicrocodePatchAddress
+ CpuMpData
->MicrocodePatchRegionSize
);
123 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (UINTN
) CpuMpData
->MicrocodePatchAddress
;
126 // Check if the microcode is for the Cpu and the version is newer
127 // and the update can be processed on the platform
129 CorrectMicrocode
= FALSE
;
130 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1) {
132 // It is the microcode header. It is not the padding data between microcode patches
133 // because the padding data should not include 0x00000001 and it should be the repeated
134 // byte format (like 0xXYXYXYXY....).
136 if (MicrocodeEntryPoint
->ProcessorSignature
.Uint32
== Eax
.Uint32
&&
137 MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
&&
138 (MicrocodeEntryPoint
->ProcessorFlags
& (1 << PlatformId
))
140 if (MicrocodeEntryPoint
->DataSize
== 0) {
141 CheckSum32
= CalculateSum32 ((UINT32
*) MicrocodeEntryPoint
, 2048);
143 CheckSum32
= CalculateSum32 (
144 (UINT32
*) MicrocodeEntryPoint
,
145 MicrocodeEntryPoint
->DataSize
+ sizeof (CPU_MICROCODE_HEADER
)
148 if (CheckSum32
== 0) {
149 CorrectMicrocode
= TRUE
;
150 ProcessorFlags
= MicrocodeEntryPoint
->ProcessorFlags
;
152 } else if ((MicrocodeEntryPoint
->DataSize
!= 0) &&
153 (MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
)) {
154 ExtendedTableLength
= MicrocodeEntryPoint
->TotalSize
- (MicrocodeEntryPoint
->DataSize
+
155 sizeof (CPU_MICROCODE_HEADER
));
156 if (ExtendedTableLength
!= 0) {
158 // Extended Table exist, check if the CPU in support list
160 ExtendedTableHeader
= (CPU_MICROCODE_EXTENDED_TABLE_HEADER
*) ((UINT8
*) (MicrocodeEntryPoint
)
161 + MicrocodeEntryPoint
->DataSize
+ sizeof (CPU_MICROCODE_HEADER
));
163 // Calculate Extended Checksum
165 if ((ExtendedTableLength
% 4) == 0) {
166 CheckSum32
= CalculateSum32 ((UINT32
*) ExtendedTableHeader
, ExtendedTableLength
);
167 if (CheckSum32
== 0) {
171 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
172 ExtendedTable
= (CPU_MICROCODE_EXTENDED_TABLE
*) (ExtendedTableHeader
+ 1);
173 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
174 CheckSum32
= CalculateSum32 ((UINT32
*) ExtendedTable
, sizeof(CPU_MICROCODE_EXTENDED_TABLE
));
175 if (CheckSum32
== 0) {
179 if ((ExtendedTable
->ProcessorSignature
.Uint32
== Eax
.Uint32
) &&
180 (ExtendedTable
->ProcessorFlag
& (1 << PlatformId
)) ) {
184 CorrectMicrocode
= TRUE
;
185 ProcessorFlags
= ExtendedTable
->ProcessorFlag
;
197 // It is the padding data between the microcode patches for microcode patches alignment.
198 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
199 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
200 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
201 // find the next possible microcode patch header.
203 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + SIZE_1KB
);
207 // Get the next patch.
209 if (MicrocodeEntryPoint
->DataSize
== 0) {
212 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
215 if (CorrectMicrocode
) {
216 LatestRevision
= MicrocodeEntryPoint
->UpdateRevision
;
217 MicrocodeData
= (VOID
*) ((UINTN
) MicrocodeEntryPoint
+ sizeof (CPU_MICROCODE_HEADER
));
220 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + TotalSize
);
221 } while (((UINTN
) MicrocodeEntryPoint
< MicrocodeEnd
));
224 if (LatestRevision
> CurrentRevision
) {
226 // BIOS only authenticate updates that contain a numerically larger revision
227 // than the currently loaded revision, where Current Signature < New Update
228 // Revision. A processor with no loaded update is considered to have a
229 // revision equal to zero.
231 ASSERT (MicrocodeData
!= NULL
);
233 MSR_IA32_BIOS_UPDT_TRIG
,
234 (UINT64
) (UINTN
) MicrocodeData
237 // Get and check new microcode signature
239 CurrentRevision
= GetCurrentMicrocodeSignature ();
240 if (CurrentRevision
!= LatestRevision
) {
241 AcquireSpinLock(&CpuMpData
->MpLock
);
242 DEBUG ((EFI_D_ERROR
, "Updated microcode signature [0x%08x] does not match \
243 loaded microcode signature [0x%08x]\n", CurrentRevision
, LatestRevision
));
244 ReleaseSpinLock(&CpuMpData
->MpLock
);
248 if (IsBspCallIn
&& (LatestRevision
!= 0)) {
250 // Save BSP processor info and microcode info for later AP use.
252 CpuMpData
->ProcessorSignature
= Eax
.Uint32
;
253 CpuMpData
->ProcessorFlags
= ProcessorFlags
;
254 CpuMpData
->MicrocodeDataAddress
= (UINTN
) MicrocodeData
;
255 CpuMpData
->MicrocodeRevision
= LatestRevision
;
256 DEBUG ((DEBUG_INFO
, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \
257 MicroData [0x%08x], Revision [0x%08x]\n", Eax
.Uint32
, ProcessorFlags
, (UINTN
) MicrocodeData
, LatestRevision
));