]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/Microcode.c
643a6f94f4a5fb1d0aee99f1da954bf12f8f96be
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
1 /** @file
2 Implementation of loading microcode on processors.
3
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
9
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.
12
13 **/
14
15 #include "MpLib.h"
16
17 /**
18 Get microcode update signature of currently loaded microcode update.
19
20 @return Microcode signature.
21 **/
22 UINT32
23 GetCurrentMicrocodeSignature (
24 VOID
25 )
26 {
27 MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;
28
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;
33 }
34
35 /**
36 Detect whether specified processor can find matching microcode patch and load it.
37
38 Microcode Payload as the following format:
39 +----------------------------------------+------------------+
40 | CPU_MICROCODE_HEADER | |
41 +----------------------------------------+ CheckSum Part1 |
42 | Microcode Binary | |
43 +----------------------------------------+------------------+
44 | CPU_MICROCODE_EXTENDED_TABLE_HEADER | |
45 +----------------------------------------+ CheckSum Part2 |
46 | CPU_MICROCODE_EXTENDED_TABLE | |
47 | ... | |
48 +----------------------------------------+------------------+
49
50 There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
51 The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
52 of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.
53
54 When we are trying to verify the CheckSum32 with extended table.
55 We should use the fields of exnteded table to replace the corresponding
56 fields in CPU_MICROCODE_HEADER structure, and recalculate the
57 CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named
58 it as CheckSum Part3.
59
60 The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER
61 and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2
62 is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.
63
64 Only ProcessorSignature, ProcessorFlag and CheckSum are different between
65 CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.
66 Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
67 When we are going to calculate CheckSum32, just should use the corresponding part
68 of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.
69
70 Notes: CheckSum32 is not a strong verification.
71 It does not guarantee that the data has not been modified.
72 CPU has its own mechanism to verify Microcode Binary part.
73
74 @param[in] CpuMpData The pointer to CPU MP Data structure.
75 @param[in] IsBspCallIn Indicate whether the caller is BSP or not.
76 **/
77 VOID
78 MicrocodeDetect (
79 IN CPU_MP_DATA *CpuMpData,
80 IN BOOLEAN IsBspCallIn
81 )
82 {
83 UINT32 ExtendedTableLength;
84 UINT32 ExtendedTableCount;
85 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
86 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
87 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
88 UINTN MicrocodeEnd;
89 UINTN Index;
90 UINT8 PlatformId;
91 CPUID_VERSION_INFO_EAX Eax;
92 UINT32 CurrentRevision;
93 UINT32 LatestRevision;
94 UINTN TotalSize;
95 UINT32 CheckSum32;
96 UINT32 InCompleteCheckSum32;
97 BOOLEAN CorrectMicrocode;
98 VOID *MicrocodeData;
99 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
100 UINT32 ProcessorFlags;
101 UINT32 ThreadId;
102
103 //
104 // set ProcessorFlags to suppress incorrect compiler/analyzer warnings
105 //
106 ProcessorFlags = 0;
107
108 if (CpuMpData->MicrocodePatchRegionSize == 0) {
109 //
110 // There is no microcode patches
111 //
112 return;
113 }
114
115 CurrentRevision = GetCurrentMicrocodeSignature ();
116 if (CurrentRevision != 0 && !IsBspCallIn) {
117 //
118 // Skip loading microcode if it has been loaded successfully
119 //
120 return;
121 }
122
123 GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
124 if (ThreadId != 0) {
125 //
126 // Skip loading microcode if it is not the first thread in one core.
127 //
128 return;
129 }
130
131 ExtendedTableLength = 0;
132 //
133 // Here data of CPUID leafs have not been collected into context buffer, so
134 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
135 //
136 AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
137
138 //
139 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
140 //
141 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
142 PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;
143
144 //
145 // Check whether AP has same processor with BSP.
146 // If yes, direct use microcode info saved by BSP.
147 //
148 if (!IsBspCallIn) {
149 if ((CpuMpData->ProcessorSignature == Eax.Uint32) &&
150 (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) {
151 MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress;
152 LatestRevision = CpuMpData->MicrocodeRevision;
153 goto Done;
154 }
155 }
156
157 LatestRevision = 0;
158 MicrocodeData = NULL;
159 MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);
160 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
161
162 do {
163 //
164 // Check if the microcode is for the Cpu and the version is newer
165 // and the update can be processed on the platform
166 //
167 CorrectMicrocode = FALSE;
168
169 if (MicrocodeEntryPoint->DataSize == 0) {
170 TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;
171 } else {
172 TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;
173 }
174
175 ///
176 /// Check overflow and whether TotalSize is aligned with 4 bytes.
177 ///
178 if ( ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
179 (TotalSize & 0x3) != 0
180 ) {
181 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
182 continue;
183 }
184
185 //
186 // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
187 //
188 InCompleteCheckSum32 = CalculateSum32 (
189 (UINT32 *) MicrocodeEntryPoint,
190 TotalSize
191 );
192 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;
193 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
194 InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;
195
196 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
197 //
198 // It is the microcode header. It is not the padding data between microcode patches
199 // because the padding data should not include 0x00000001 and it should be the repeated
200 // byte format (like 0xXYXYXYXY....).
201 //
202 if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
203 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
204 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
205 ) {
206 //
207 // Calculate CheckSum Part1.
208 //
209 CheckSum32 = InCompleteCheckSum32;
210 CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
211 CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
212 CheckSum32 += MicrocodeEntryPoint->Checksum;
213 if (CheckSum32 == 0) {
214 CorrectMicrocode = TRUE;
215 ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;
216 }
217 } else if ((MicrocodeEntryPoint->DataSize != 0) &&
218 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
219 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
220 sizeof (CPU_MICROCODE_HEADER));
221 if (ExtendedTableLength != 0) {
222 //
223 // Extended Table exist, check if the CPU in support list
224 //
225 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
226 + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
227 //
228 // Calculate Extended Checksum
229 //
230 if ((ExtendedTableLength % 4) == 0) {
231 //
232 // Calculate CheckSum Part2.
233 //
234 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
235 if (CheckSum32 == 0) {
236 //
237 // Checksum correct
238 //
239 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
240 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
241 for (Index = 0; Index < ExtendedTableCount; Index ++) {
242 //
243 // Calculate CheckSum Part3.
244 //
245 CheckSum32 = InCompleteCheckSum32;
246 CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
247 CheckSum32 += ExtendedTable->ProcessorFlag;
248 CheckSum32 += ExtendedTable->Checksum;
249 if (CheckSum32 == 0) {
250 //
251 // Verify Header
252 //
253 if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
254 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
255 //
256 // Find one
257 //
258 CorrectMicrocode = TRUE;
259 ProcessorFlags = ExtendedTable->ProcessorFlag;
260 break;
261 }
262 }
263 ExtendedTable ++;
264 }
265 }
266 }
267 }
268 }
269 } else {
270 //
271 // It is the padding data between the microcode patches for microcode patches alignment.
272 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
273 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
274 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
275 // find the next possible microcode patch header.
276 //
277 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
278 continue;
279 }
280 //
281 // Get the next patch.
282 //
283 if (MicrocodeEntryPoint->DataSize == 0) {
284 TotalSize = 2048;
285 } else {
286 TotalSize = MicrocodeEntryPoint->TotalSize;
287 }
288
289 if (CorrectMicrocode) {
290 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
291 MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
292 }
293
294 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
295 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
296
297 Done:
298 if (LatestRevision > CurrentRevision) {
299 //
300 // BIOS only authenticate updates that contain a numerically larger revision
301 // than the currently loaded revision, where Current Signature < New Update
302 // Revision. A processor with no loaded update is considered to have a
303 // revision equal to zero.
304 //
305 ASSERT (MicrocodeData != NULL);
306 AsmWriteMsr64 (
307 MSR_IA32_BIOS_UPDT_TRIG,
308 (UINT64) (UINTN) MicrocodeData
309 );
310 //
311 // Get and check new microcode signature
312 //
313 CurrentRevision = GetCurrentMicrocodeSignature ();
314 if (CurrentRevision != LatestRevision) {
315 AcquireSpinLock(&CpuMpData->MpLock);
316 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
317 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
318 ReleaseSpinLock(&CpuMpData->MpLock);
319 }
320 }
321
322 if (IsBspCallIn && (LatestRevision != 0)) {
323 //
324 // Save BSP processor info and microcode info for later AP use.
325 //
326 CpuMpData->ProcessorSignature = Eax.Uint32;
327 CpuMpData->ProcessorFlags = ProcessorFlags;
328 CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData;
329 CpuMpData->MicrocodeRevision = LatestRevision;
330 DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \
331 MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));
332 }
333 }