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