]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/Microcode.c
StandaloneMmPkg: Apply uncrustify changes
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
CommitLineData
94f63c76
JF
1/** @file\r
2 Implementation of loading microcode on processors.\r
3\r
bce03284 4 Copyright (c) 2015 - 2021, 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
94f63c76
JF
11/**\r
12 Detect whether specified processor can find matching microcode patch and load it.\r
13\r
e1ed5573
HW
14 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
15 @param[in] ProcessorNumber The handle number of the processor. The range is\r
16 from 0 to the total number of logical processors\r
17 minus 1.\r
94f63c76
JF
18**/\r
19VOID\r
20MicrocodeDetect (\r
2a089134 21 IN CPU_MP_DATA *CpuMpData,\r
e1ed5573 22 IN UINTN ProcessorNumber\r
94f63c76
JF
23 )\r
24{\r
bce03284 25 CPU_MICROCODE_HEADER *Microcode;\r
94f63c76 26 UINTN MicrocodeEnd;\r
bce03284 27 CPU_AP_DATA *BspData;\r
94f63c76 28 UINT32 LatestRevision;\r
bce03284 29 CPU_MICROCODE_HEADER *LatestMicrocode;\r
f63a3e28 30 UINT32 ThreadId;\r
bce03284 31 EDKII_PEI_MICROCODE_CPU_ID MicrocodeCpuId;\r
94f63c76 32\r
1e3f7a37 33 if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
94f63c76
JF
34 //\r
35 // There is no microcode patches\r
36 //\r
37 return;\r
38 }\r
39\r
f63a3e28
ED
40 GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);\r
41 if (ThreadId != 0) {\r
42 //\r
43 // Skip loading microcode if it is not the first thread in one core.\r
44 //\r
45 return;\r
46 }\r
47\r
bce03284 48 GetProcessorMicrocodeCpuId (&MicrocodeCpuId);\r
94f63c76 49\r
bce03284 50 if (ProcessorNumber != (UINTN) CpuMpData->BspNumber) {\r
fd30b007 51 //\r
bce03284
RN
52 // Direct use microcode of BSP if AP is the same as BSP.\r
53 // Assume BSP calls this routine() before AP.\r
fd30b007 54 //\r
bce03284
RN
55 BspData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);\r
56 if ((BspData->ProcessorSignature == MicrocodeCpuId.ProcessorSignature) &&\r
57 (BspData->PlatformId == MicrocodeCpuId.PlatformId) &&\r
58 (BspData->MicrocodeEntryAddr != 0)) {\r
59 LatestMicrocode = (CPU_MICROCODE_HEADER *)(UINTN) BspData->MicrocodeEntryAddr;\r
60 LatestRevision = LatestMicrocode->UpdateRevision;\r
61 goto LoadMicrocode;\r
2a089134
ED
62 }\r
63 }\r
64\r
bce03284
RN
65 //\r
66 // BSP or AP which is different from BSP runs here\r
67 // Use 0 as the starting revision to search for microcode because MicrocodePatchInfo HOB needs\r
68 // the latest microcode location even it's loaded to the processor.\r
69 //\r
70 LatestRevision = 0;\r
71 LatestMicrocode = NULL;\r
72 Microcode = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
73 MicrocodeEnd = (UINTN) Microcode + (UINTN) CpuMpData->MicrocodePatchRegionSize;\r
b6f67b4d 74\r
94f63c76 75 do {\r
bce03284 76 if (!IsValidMicrocode (Microcode, MicrocodeEnd - (UINTN) Microcode, LatestRevision, &MicrocodeCpuId, 1, TRUE)) {\r
94f63c76
JF
77 //\r
78 // It is the padding data between the microcode patches for microcode patches alignment.\r
79 // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
80 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
81 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
82 // find the next possible microcode patch header.\r
83 //\r
bce03284 84 Microcode = (CPU_MICROCODE_HEADER *) ((UINTN) Microcode + SIZE_1KB);\r
94f63c76
JF
85 continue;\r
86 }\r
bce03284
RN
87 LatestMicrocode = Microcode;\r
88 LatestRevision = LatestMicrocode->UpdateRevision;\r
94f63c76 89\r
bce03284
RN
90 Microcode = (CPU_MICROCODE_HEADER *) (((UINTN) Microcode) + GetMicrocodeLength (Microcode));\r
91 } while ((UINTN) Microcode < MicrocodeEnd);\r
94f63c76 92\r
bce03284 93LoadMicrocode:\r
e1ed5573
HW
94 if (LatestRevision != 0) {\r
95 //\r
bce03284
RN
96 // Save the detected microcode patch entry address (including the microcode\r
97 // patch header) for each processor even it's the same as the loaded one.\r
e1ed5573
HW
98 // It will be used when building the microcode patch cache HOB.\r
99 //\r
bce03284 100 CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN) LatestMicrocode;\r
e1ed5573
HW
101 }\r
102\r
bce03284 103 if (LatestRevision > GetProcessorMicrocodeSignature ()) {\r
94f63c76
JF
104 //\r
105 // BIOS only authenticate updates that contain a numerically larger revision\r
106 // than the currently loaded revision, where Current Signature < New Update\r
107 // Revision. A processor with no loaded update is considered to have a\r
108 // revision equal to zero.\r
109 //\r
bce03284 110 LoadMicrocode (LatestMicrocode);\r
d786a172 111 }\r
dd017041 112 //\r
bce03284 113 // It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.\r
dd017041 114 //\r
bce03284 115 CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();\r
dd017041
SF
116}\r
117\r
dd017041
SF
118/**\r
119 Actual worker function that shadows the required microcode patches into memory.\r
d786a172
HW
120\r
121 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
122 @param[in] Patches The pointer to an array of information on\r
123 the microcode patches that will be loaded\r
124 into memory.\r
125 @param[in] PatchCount The number of microcode patches that will\r
126 be loaded into memory.\r
127 @param[in] TotalLoadSize The total size of all the microcode patches\r
128 to be loaded.\r
129**/\r
130VOID\r
dd017041 131ShadowMicrocodePatchWorker (\r
d786a172
HW
132 IN OUT CPU_MP_DATA *CpuMpData,\r
133 IN MICROCODE_PATCH_INFO *Patches,\r
134 IN UINTN PatchCount,\r
135 IN UINTN TotalLoadSize\r
136 )\r
137{\r
138 UINTN Index;\r
139 VOID *MicrocodePatchInRam;\r
140 UINT8 *Walker;\r
141\r
142 ASSERT ((Patches != NULL) && (PatchCount != 0));\r
143\r
144 MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));\r
145 if (MicrocodePatchInRam == NULL) {\r
146 return;\r
147 }\r
148\r
149 //\r
150 // Load all the required microcode patches into memory\r
151 //\r
152 for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {\r
153 CopyMem (\r
154 Walker,\r
155 (VOID *) Patches[Index].Address,\r
156 Patches[Index].Size\r
157 );\r
08a475df 158 Walker += Patches[Index].Size;\r
d786a172
HW
159 }\r
160\r
161 //\r
162 // Update the microcode patch related fields in CpuMpData\r
163 //\r
164 CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;\r
165 CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;\r
166\r
167 DEBUG ((\r
168 DEBUG_INFO,\r
169 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
170 __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize\r
171 ));\r
172\r
173 return;\r
174}\r
175\r
176/**\r
dd017041
SF
177 Shadow the required microcode patches data into memory according to PCD\r
178 PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.\r
d786a172
HW
179\r
180 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
181**/\r
182VOID\r
dd017041 183ShadowMicrocodePatchByPcd (\r
d786a172
HW
184 IN OUT CPU_MP_DATA *CpuMpData\r
185 )\r
186{\r
bce03284 187 UINTN Index;\r
d786a172
HW
188 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
189 UINTN MicrocodeEnd;\r
d786a172 190 UINTN TotalSize;\r
d786a172
HW
191 MICROCODE_PATCH_INFO *PatchInfoBuffer;\r
192 UINTN MaxPatchNumber;\r
193 UINTN PatchCount;\r
194 UINTN TotalLoadSize;\r
bce03284
RN
195 EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds;\r
196 BOOLEAN Valid;\r
d786a172
HW
197\r
198 //\r
199 // Initialize the microcode patch related fields in CpuMpData as the values\r
200 // specified by the PCD pair. If the microcode patches are loaded into memory,\r
201 // these fields will be updated.\r
202 //\r
203 CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
204 CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
205\r
206 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
207 MicrocodeEnd = (UINTN) MicrocodeEntryPoint +\r
208 (UINTN) CpuMpData->MicrocodePatchRegionSize;\r
209 if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {\r
210 //\r
211 // There is no microcode patches\r
212 //\r
213 return;\r
214 }\r
215\r
216 PatchCount = 0;\r
217 MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;\r
218 TotalLoadSize = 0;\r
219 PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));\r
220 if (PatchInfoBuffer == NULL) {\r
221 return;\r
222 }\r
223\r
bce03284
RN
224 MicrocodeCpuIds = AllocatePages (\r
225 EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID))\r
226 );\r
227 if (MicrocodeCpuIds == NULL) {\r
228 FreePool (PatchInfoBuffer);\r
229 return;\r
230 }\r
231\r
232 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
233 MicrocodeCpuIds[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;\r
234 MicrocodeCpuIds[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;\r
235 }\r
236\r
d786a172
HW
237 //\r
238 // Process the header of each microcode patch within the region.\r
239 // The purpose is to decide which microcode patch(es) will be loaded into memory.\r
bce03284 240 // Microcode checksum is not verified because it's slow when performing on flash.\r
d786a172
HW
241 //\r
242 do {\r
bce03284
RN
243 Valid = IsValidMicrocode (\r
244 MicrocodeEntryPoint,\r
245 MicrocodeEnd - (UINTN) MicrocodeEntryPoint,\r
246 0,\r
247 MicrocodeCpuIds,\r
248 CpuMpData->CpuCount,\r
249 FALSE\r
250 );\r
251 if (!Valid) {\r
d786a172
HW
252 //\r
253 // Padding data between the microcode patches, skip 1KB to check next entry.\r
254 //\r
255 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
256 continue;\r
257 }\r
258\r
bce03284
RN
259 PatchCount++;\r
260 if (PatchCount > MaxPatchNumber) {\r
d786a172 261 //\r
bce03284
RN
262 // Current 'PatchInfoBuffer' cannot hold the information, double the size\r
263 // and allocate a new buffer.\r
d786a172 264 //\r
bce03284 265 if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {\r
d786a172 266 //\r
bce03284 267 // Overflow check for MaxPatchNumber\r
d786a172 268 //\r
bce03284 269 goto OnExit;\r
d786a172
HW
270 }\r
271\r
bce03284
RN
272 PatchInfoBuffer = ReallocatePool (\r
273 MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
274 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
275 PatchInfoBuffer\r
276 );\r
277 if (PatchInfoBuffer == NULL) {\r
278 goto OnExit;\r
279 }\r
280 MaxPatchNumber = MaxPatchNumber * 2;\r
d786a172
HW
281 }\r
282\r
bce03284
RN
283 TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);\r
284\r
285 //\r
286 // Store the information of this microcode patch\r
287 //\r
288 PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;\r
289 PatchInfoBuffer[PatchCount - 1].Size = TotalSize;\r
290 TotalLoadSize += TotalSize;\r
291\r
d786a172
HW
292 //\r
293 // Process the next microcode patch\r
294 //\r
bce03284
RN
295 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) ((UINTN) MicrocodeEntryPoint + TotalSize);\r
296 } while ((UINTN) MicrocodeEntryPoint < MicrocodeEnd);\r
d786a172
HW
297\r
298 if (PatchCount != 0) {\r
299 DEBUG ((\r
300 DEBUG_INFO,\r
301 "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",\r
302 __FUNCTION__, PatchCount, TotalLoadSize\r
303 ));\r
304\r
dd017041 305 ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
d786a172
HW
306 }\r
307\r
308OnExit:\r
309 if (PatchInfoBuffer != NULL) {\r
310 FreePool (PatchInfoBuffer);\r
311 }\r
bce03284 312 FreePages (MicrocodeCpuIds, EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID)));\r
d786a172 313}\r
dd017041 314\r
dd017041
SF
315/**\r
316 Shadow the required microcode patches data into memory.\r
317\r
318 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
319**/\r
320VOID\r
321ShadowMicrocodeUpdatePatch (\r
322 IN OUT CPU_MP_DATA *CpuMpData\r
323 )\r
324{\r
325 EFI_STATUS Status;\r
326\r
c788c2b1 327 Status = PlatformShadowMicrocode (CpuMpData);\r
dd017041
SF
328 if (EFI_ERROR (Status)) {\r
329 ShadowMicrocodePatchByPcd (CpuMpData);\r
330 }\r
331}\r
348a34d9
HW
332\r
333/**\r
334 Get the cached microcode patch base address and size from the microcode patch\r
335 information cache HOB.\r
336\r
337 @param[out] Address Base address of the microcode patches data.\r
338 It will be updated if the microcode patch\r
339 information cache HOB is found.\r
340 @param[out] RegionSize Size of the microcode patches data.\r
341 It will be updated if the microcode patch\r
342 information cache HOB is found.\r
343\r
344 @retval TRUE The microcode patch information cache HOB is found.\r
345 @retval FALSE The microcode patch information cache HOB is not found.\r
346\r
347**/\r
348BOOLEAN\r
349GetMicrocodePatchInfoFromHob (\r
350 UINT64 *Address,\r
351 UINT64 *RegionSize\r
352 )\r
353{\r
354 EFI_HOB_GUID_TYPE *GuidHob;\r
355 EDKII_MICROCODE_PATCH_HOB *MicrocodePathHob;\r
356\r
357 GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);\r
358 if (GuidHob == NULL) {\r
359 DEBUG((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));\r
360 return FALSE;\r
361 }\r
362\r
363 MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);\r
364\r
365 *Address = MicrocodePathHob->MicrocodePatchAddress;\r
366 *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;\r
367\r
368 DEBUG((\r
369 DEBUG_INFO, "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",\r
370 __FUNCTION__, *Address, *RegionSize\r
371 ));\r
372\r
373 return TRUE;\r
374}\r