TianoCore EDK2 master
Microcode.c
Go to the documentation of this file.
1
9#include "MpLib.h"
10
19VOID
21 IN CPU_MP_DATA *CpuMpData,
22 IN UINTN ProcessorNumber
23 )
24{
25 CPU_MICROCODE_HEADER *Microcode;
26 UINTN MicrocodeEnd;
27 CPU_AP_DATA *BspData;
28 UINT32 LatestRevision;
29 CPU_MICROCODE_HEADER *LatestMicrocode;
30 UINT32 ThreadId;
31 EDKII_PEI_MICROCODE_CPU_ID MicrocodeCpuId;
32
33 if (CpuMpData->MicrocodePatchRegionSize == 0) {
34 //
35 // There is no microcode patches
36 //
37 return;
38 }
39
41 if (ThreadId != 0) {
42 //
43 // Skip loading microcode if it is not the first thread in one core.
44 //
45 return;
46 }
47
48 GetProcessorMicrocodeCpuId (&MicrocodeCpuId);
49
50 if (ProcessorNumber != (UINTN)CpuMpData->BspNumber) {
51 //
52 // Direct use microcode of BSP if AP is the same as BSP.
53 // Assume BSP calls this routine() before AP.
54 //
55 BspData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
56 if ((BspData->ProcessorSignature == MicrocodeCpuId.ProcessorSignature) &&
57 (BspData->PlatformId == MicrocodeCpuId.PlatformId) &&
58 (BspData->MicrocodeEntryAddr != 0))
59 {
60 LatestMicrocode = (CPU_MICROCODE_HEADER *)(UINTN)BspData->MicrocodeEntryAddr;
61 LatestRevision = LatestMicrocode->UpdateRevision;
62 goto LoadMicrocode;
63 }
64 }
65
66 //
67 // BSP or AP which is different from BSP runs here
68 // Use 0 as the starting revision to search for microcode because MicrocodePatchInfo HOB needs
69 // the latest microcode location even it's loaded to the processor.
70 //
71 LatestRevision = 0;
72 LatestMicrocode = NULL;
73 Microcode = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;
74 MicrocodeEnd = (UINTN)Microcode + (UINTN)CpuMpData->MicrocodePatchRegionSize;
75
76 do {
77 if (!IsValidMicrocode (Microcode, MicrocodeEnd - (UINTN)Microcode, LatestRevision, &MicrocodeCpuId, 1, TRUE)) {
78 //
79 // It is the padding data between the microcode patches for microcode patches alignment.
80 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
81 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
82 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
83 // find the next possible microcode patch header.
84 //
85 Microcode = (CPU_MICROCODE_HEADER *)((UINTN)Microcode + SIZE_1KB);
86 continue;
87 }
88
89 LatestMicrocode = Microcode;
90 LatestRevision = LatestMicrocode->UpdateRevision;
91
92 Microcode = (CPU_MICROCODE_HEADER *)(((UINTN)Microcode) + GetMicrocodeLength (Microcode));
93 } while ((UINTN)Microcode < MicrocodeEnd);
94
96 if (LatestRevision != 0) {
97 //
98 // Save the detected microcode patch entry address (including the microcode
99 // patch header) for each processor even it's the same as the loaded one.
100 // It will be used when building the microcode patch cache HOB.
101 //
102 CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN)LatestMicrocode;
103 }
104
105 if (LatestRevision > GetProcessorMicrocodeSignature ()) {
106 //
107 // BIOS only authenticate updates that contain a numerically larger revision
108 // than the currently loaded revision, where Current Signature < New Update
109 // Revision. A processor with no loaded update is considered to have a
110 // revision equal to zero.
111 //
112 LoadMicrocode (LatestMicrocode);
113 }
114
115 //
116 // It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.
117 //
118 CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();
119}
120
133VOID
135 IN OUT CPU_MP_DATA *CpuMpData,
136 IN MICROCODE_PATCH_INFO *Patches,
137 IN UINTN PatchCount,
138 IN UINTN TotalLoadSize
139 )
140{
141 UINTN Index;
142 VOID *MicrocodePatchInRam;
143 UINT8 *Walker;
144
145 ASSERT ((Patches != NULL) && (PatchCount != 0));
146
147 MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
148 if (MicrocodePatchInRam == NULL) {
149 return;
150 }
151
152 //
153 // Load all the required microcode patches into memory
154 //
155 for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
156 CopyMem (
157 Walker,
158 (VOID *)Patches[Index].Address,
159 Patches[Index].Size
160 );
161 Walker += Patches[Index].Size;
162 }
163
164 //
165 // Update the microcode patch related fields in CpuMpData
166 //
167 CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;
168 CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;
169
170 DEBUG ((
171 DEBUG_INFO,
172 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
173 __FUNCTION__,
174 CpuMpData->MicrocodePatchAddress,
175 CpuMpData->MicrocodePatchRegionSize
176 ));
177
178 return;
179}
180
187VOID
189 IN OUT CPU_MP_DATA *CpuMpData
190 )
191{
192 UINTN Index;
193 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
194 UINTN MicrocodeEnd;
195 UINTN TotalSize;
196 MICROCODE_PATCH_INFO *PatchInfoBuffer;
197 UINTN MaxPatchNumber;
198 UINTN PatchCount;
199 UINTN TotalLoadSize;
200 EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds;
201 BOOLEAN Valid;
202
203 //
204 // Initialize the microcode patch related fields in CpuMpData as the values
205 // specified by the PCD pair. If the microcode patches are loaded into memory,
206 // these fields will be updated.
207 //
208 CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
209 CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
210
211 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;
212 MicrocodeEnd = (UINTN)MicrocodeEntryPoint +
213 (UINTN)CpuMpData->MicrocodePatchRegionSize;
214 if ((MicrocodeEntryPoint == NULL) || ((UINTN)MicrocodeEntryPoint == MicrocodeEnd)) {
215 //
216 // There is no microcode patches
217 //
218 return;
219 }
220
221 PatchCount = 0;
222 MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;
223 TotalLoadSize = 0;
224 PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
225 if (PatchInfoBuffer == NULL) {
226 return;
227 }
228
229 MicrocodeCpuIds = AllocatePages (
230 EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID))
231 );
232 if (MicrocodeCpuIds == NULL) {
233 FreePool (PatchInfoBuffer);
234 return;
235 }
236
237 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
238 MicrocodeCpuIds[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
239 MicrocodeCpuIds[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
240 }
241
242 //
243 // Process the header of each microcode patch within the region.
244 // The purpose is to decide which microcode patch(es) will be loaded into memory.
245 // Microcode checksum is not verified because it's slow when performing on flash.
246 //
247 do {
248 Valid = IsValidMicrocode (
249 MicrocodeEntryPoint,
250 MicrocodeEnd - (UINTN)MicrocodeEntryPoint,
251 0,
252 MicrocodeCpuIds,
253 CpuMpData->CpuCount,
254 FALSE
255 );
256 if (!Valid) {
257 //
258 // Padding data between the microcode patches, skip 1KB to check next entry.
259 //
260 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB);
261 continue;
262 }
263
264 PatchCount++;
265 if (PatchCount > MaxPatchNumber) {
266 //
267 // Current 'PatchInfoBuffer' cannot hold the information, double the size
268 // and allocate a new buffer.
269 //
270 if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
271 //
272 // Overflow check for MaxPatchNumber
273 //
274 goto OnExit;
275 }
276
277 PatchInfoBuffer = ReallocatePool (
278 MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
279 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
280 PatchInfoBuffer
281 );
282 if (PatchInfoBuffer == NULL) {
283 goto OnExit;
284 }
285
286 MaxPatchNumber = MaxPatchNumber * 2;
287 }
288
289 TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);
290
291 //
292 // Store the information of this microcode patch
293 //
294 PatchInfoBuffer[PatchCount - 1].Address = (UINTN)MicrocodeEntryPoint;
295 PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
296 TotalLoadSize += TotalSize;
297
298 //
299 // Process the next microcode patch
300 //
301 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)((UINTN)MicrocodeEntryPoint + TotalSize);
302 } while ((UINTN)MicrocodeEntryPoint < MicrocodeEnd);
303
304 if (PatchCount != 0) {
305 DEBUG ((
306 DEBUG_INFO,
307 "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
308 __FUNCTION__,
309 PatchCount,
310 TotalLoadSize
311 ));
312
313 ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
314 }
315
316OnExit:
317 if (PatchInfoBuffer != NULL) {
318 FreePool (PatchInfoBuffer);
319 }
320
321 FreePages (MicrocodeCpuIds, EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID)));
322}
323
329VOID
331 IN OUT CPU_MP_DATA *CpuMpData
332 )
333{
334 EFI_STATUS Status;
335
336 Status = PlatformShadowMicrocode (CpuMpData);
337 if (EFI_ERROR (Status)) {
338 ShadowMicrocodePatchByPcd (CpuMpData);
339 }
340}
341
357BOOLEAN
359 UINT64 *Address,
360 UINT64 *RegionSize
361 )
362{
363 EFI_HOB_GUID_TYPE *GuidHob;
364 EDKII_MICROCODE_PATCH_HOB *MicrocodePathHob;
365
366 GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);
367 if (GuidHob == NULL) {
368 DEBUG ((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));
369 return FALSE;
370 }
371
372 MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);
373
374 *Address = MicrocodePathHob->MicrocodePatchAddress;
375 *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;
376
377 DEBUG ((
378 DEBUG_INFO,
379 "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",
380 __FUNCTION__,
381 *Address,
382 *RegionSize
383 ));
384
385 return TRUE;
386}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
#define NULL
Definition: Base.h:312
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define DEBUG(Expression)
Definition: DebugLib.h:417
#define ASSERT(Expression)
Definition: DebugLib.h:391
EFI_STATUS PlatformShadowMicrocode(IN OUT CPU_MP_DATA *CpuMpData)
Definition: DxeMpLib.c:986
#define MAX_UINTN
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID *EFIAPI ReallocatePool(IN UINTN OldSize, IN UINTN NewSize, IN VOID *OldBuffer OPTIONAL)
UINT32 EFIAPI LoadMicrocode(IN VOID *FsptUpdDataPtr)
#define GET_GUID_HOB_DATA(HobStart)
Definition: HobLib.h:544
UINT32 EFIAPI GetInitialApicId(VOID)
Definition: BaseXApicLib.c:299
VOID EFIAPI GetProcessorLocationByApicId(IN UINT32 InitialApicId, OUT UINT32 *Package OPTIONAL, OUT UINT32 *Core OPTIONAL, OUT UINT32 *Thread OPTIONAL)
Definition: BaseXApicLib.c:969
VOID ShadowMicrocodeUpdatePatch(IN OUT CPU_MP_DATA *CpuMpData)
Definition: Microcode.c:330
VOID MicrocodeDetect(IN CPU_MP_DATA *CpuMpData, IN UINTN ProcessorNumber)
Definition: Microcode.c:20
BOOLEAN GetMicrocodePatchInfoFromHob(UINT64 *Address, UINT64 *RegionSize)
Definition: Microcode.c:358
VOID ShadowMicrocodePatchByPcd(IN OUT CPU_MP_DATA *CpuMpData)
Definition: Microcode.c:188
VOID ShadowMicrocodePatchWorker(IN OUT CPU_MP_DATA *CpuMpData, IN MICROCODE_PATCH_INFO *Patches, IN UINTN PatchCount, IN UINTN TotalLoadSize)
Definition: Microcode.c:134
BOOLEAN EFIAPI IsValidMicrocode(IN CPU_MICROCODE_HEADER *Microcode, IN UINTN MicrocodeLength, IN UINT32 MinimumRevision, IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds, IN UINTN MicrocodeCpuIdCount, IN BOOLEAN VerifyChecksum)
Definition: MicrocodeLib.c:186
VOID EFIAPI GetProcessorMicrocodeCpuId(EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId)
Definition: MicrocodeLib.c:43
UINT32 EFIAPI GetMicrocodeLength(IN CPU_MICROCODE_HEADER *Microcode)
Definition: MicrocodeLib.c:73
UINT32 EFIAPI GetProcessorMicrocodeSignature(VOID)
Definition: MicrocodeLib.c:24
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
VOID *EFIAPI AllocatePages(IN UINTN Pages)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:28
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:197