]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
BaseTools:Add import in FvImageSection
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeFmp.c
1 /** @file
2 Produce FMP instance for Microcode.
3
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "MicrocodeUpdate.h"
10
11 //
12 // MicrocodeFmp driver private data
13 //
14 MICROCODE_FMP_PRIVATE_DATA *mMicrocodeFmpPrivate = NULL;
15
16 EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol = {
17 FmpGetImageInfo,
18 FmpGetImage,
19 FmpSetImage,
20 FmpCheckImage,
21 FmpGetPackageInfo,
22 FmpSetPackageInfo
23 };
24
25 /**
26 Initialize Microcode Descriptor.
27
28 @param[in] MicrocodeFmpPrivate private data structure to be initialized.
29
30 @return EFI_SUCCESS Microcode Descriptor is initialized.
31 **/
32 EFI_STATUS
33 InitializeMicrocodeDescriptor (
34 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
35 );
36
37 /**
38 Returns information about the current firmware image(s) of the device.
39
40 This function allows a copy of the current firmware image to be created and saved.
41 The saved copy could later been used, for example, in firmware image recovery or rollback.
42
43 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
44 @param[in, out] ImageInfoSize A pointer to the size, in bytes, of the ImageInfo buffer.
45 On input, this is the size of the buffer allocated by the caller.
46 On output, it is the size of the buffer returned by the firmware
47 if the buffer was large enough, or the size of the buffer needed
48 to contain the image(s) information if the buffer was too small.
49 @param[in, out] ImageInfo A pointer to the buffer in which firmware places the current image(s)
50 information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
51 @param[out] DescriptorVersion A pointer to the location in which firmware returns the version number
52 associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
53 @param[out] DescriptorCount A pointer to the location in which firmware returns the number of
54 descriptors or firmware images within this device.
55 @param[out] DescriptorSize A pointer to the location in which firmware returns the size, in bytes,
56 of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
57 @param[out] PackageVersion A version number that represents all the firmware images in the device.
58 The format is vendor specific and new version must have a greater value
59 than the old version. If PackageVersion is not supported, the value is
60 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison
61 is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates
62 that package version update is in progress.
63 @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing the
64 package version name. The buffer is allocated by this function with
65 AllocatePool(), and it is the caller's responsibility to free it with a call
66 to FreePool().
67
68 @retval EFI_SUCCESS The device was successfully updated with the new image.
69 @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. The current buffer size
70 needed to hold the image(s) information is returned in ImageInfoSize.
71 @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL.
72 @retval EFI_DEVICE_ERROR Valid information could not be returned. Possible corrupted image.
73
74 **/
75 EFI_STATUS
76 EFIAPI
77 FmpGetImageInfo (
78 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
79 IN OUT UINTN *ImageInfoSize,
80 IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
81 OUT UINT32 *DescriptorVersion,
82 OUT UINT8 *DescriptorCount,
83 OUT UINTN *DescriptorSize,
84 OUT UINT32 *PackageVersion,
85 OUT CHAR16 **PackageVersionName
86 )
87 {
88 MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
89 UINTN Index;
90
91 MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
92
93 if(ImageInfoSize == NULL) {
94 return EFI_INVALID_PARAMETER;
95 }
96
97 if (*ImageInfoSize < sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount) {
98 *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount;
99 return EFI_BUFFER_TOO_SMALL;
100 }
101
102 if (ImageInfo == NULL ||
103 DescriptorVersion == NULL ||
104 DescriptorCount == NULL ||
105 DescriptorSize == NULL ||
106 PackageVersion == NULL ||
107 PackageVersionName == NULL) {
108 return EFI_INVALID_PARAMETER;
109 }
110
111 *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount;
112 *DescriptorSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR);
113 *DescriptorCount = MicrocodeFmpPrivate->DescriptorCount;
114 *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
115
116 //
117 // supports 1 ImageInfo descriptor
118 //
119 CopyMem(&ImageInfo[0], MicrocodeFmpPrivate->ImageDescriptor, sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount);
120 for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
121 if ((ImageInfo[Index].AttributesSetting & IMAGE_ATTRIBUTE_IN_USE) != 0) {
122 ImageInfo[Index].LastAttemptVersion = MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion;
123 ImageInfo[Index].LastAttemptStatus = MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus;
124 }
125 }
126
127 //
128 // package version
129 //
130 *PackageVersion = MicrocodeFmpPrivate->PackageVersion;
131 if (MicrocodeFmpPrivate->PackageVersionName != NULL) {
132 *PackageVersionName = AllocateCopyPool(StrSize(MicrocodeFmpPrivate->PackageVersionName), MicrocodeFmpPrivate->PackageVersionName);
133 }
134
135 return EFI_SUCCESS;
136 }
137
138 /**
139 Retrieves a copy of the current firmware image of the device.
140
141 This function allows a copy of the current firmware image to be created and saved.
142 The saved copy could later been used, for example, in firmware image recovery or rollback.
143
144 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
145 @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
146 The number is between 1 and DescriptorCount.
147 @param[in,out] Image Points to the buffer where the current image is copied to.
148 @param[in,out] ImageSize On entry, points to the size of the buffer pointed to by Image, in bytes.
149 On return, points to the length of the image, in bytes.
150
151 @retval EFI_SUCCESS The device was successfully updated with the new image.
152 @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to hold the
153 image. The current buffer size needed to hold the image is returned
154 in ImageSize.
155 @retval EFI_INVALID_PARAMETER The Image was NULL.
156 @retval EFI_NOT_FOUND The current image is not copied to the buffer.
157 @retval EFI_UNSUPPORTED The operation is not supported.
158 @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
159
160 **/
161 EFI_STATUS
162 EFIAPI
163 FmpGetImage (
164 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
165 IN UINT8 ImageIndex,
166 IN OUT VOID *Image,
167 IN OUT UINTN *ImageSize
168 )
169 {
170 MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
171 MICROCODE_INFO *MicrocodeInfo;
172
173 if (Image == NULL || ImageSize == NULL) {
174 return EFI_INVALID_PARAMETER;
175 }
176
177 MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
178
179 if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || ImageSize == NULL || Image == NULL) {
180 return EFI_INVALID_PARAMETER;
181 }
182
183 MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[ImageIndex - 1];
184
185 if (*ImageSize < MicrocodeInfo->TotalSize) {
186 *ImageSize = MicrocodeInfo->TotalSize;
187 return EFI_BUFFER_TOO_SMALL;
188 }
189
190 *ImageSize = MicrocodeInfo->TotalSize;
191 CopyMem (Image, MicrocodeInfo->MicrocodeEntryPoint, MicrocodeInfo->TotalSize);
192 return EFI_SUCCESS;
193 }
194
195 /**
196 Updates the firmware image of the device.
197
198 This function updates the hardware with the new firmware image.
199 This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
200 If the firmware image is updatable, the function should perform the following minimal validations
201 before proceeding to do the firmware image update.
202 - Validate the image authentication if image has attribute
203 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
204 EFI_SECURITY_VIOLATION if the validation fails.
205 - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
206 the image is unsupported. The function can optionally provide more detailed information on
207 why the image is not a supported image.
208 - Validate the data from VendorCode if not null. Image validation must be performed before
209 VendorCode data validation. VendorCode data is ignored or considered invalid if image
210 validation failed. The function returns EFI_ABORTED if the data is invalid.
211
212 VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
213 the caller did not specify the policy or use the default policy. As an example, vendor can implement
214 a policy to allow an option to force a firmware image update when the abort reason is due to the new
215 firmware image version is older than the current firmware image version or bad image checksum.
216 Sensitive operations such as those wiping the entire firmware image and render the device to be
217 non-functional should be encoded in the image itself rather than passed with the VendorCode.
218 AbortReason enables vendor to have the option to provide a more detailed description of the abort
219 reason to the caller.
220
221 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
222 @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
223 The number is between 1 and DescriptorCount.
224 @param[in] Image Points to the new image.
225 @param[in] ImageSize Size of the new image in bytes.
226 @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy.
227 Null indicates the caller did not specify the policy or use the default policy.
228 @param[in] Progress A function used by the driver to report the progress of the firmware update.
229 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
230 details for the aborted operation. The buffer is allocated by this function
231 with AllocatePool(), and it is the caller's responsibility to free it with a
232 call to FreePool().
233
234 @retval EFI_SUCCESS The device was successfully updated with the new image.
235 @retval EFI_ABORTED The operation is aborted.
236 @retval EFI_INVALID_PARAMETER The Image was NULL.
237 @retval EFI_UNSUPPORTED The operation is not supported.
238 @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
239
240 **/
241 EFI_STATUS
242 EFIAPI
243 FmpSetImage (
244 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
245 IN UINT8 ImageIndex,
246 IN CONST VOID *Image,
247 IN UINTN ImageSize,
248 IN CONST VOID *VendorCode,
249 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
250 OUT CHAR16 **AbortReason
251 )
252 {
253 EFI_STATUS Status;
254 EFI_STATUS VarStatus;
255 MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
256
257 if (Image == NULL || AbortReason == NULL) {
258 return EFI_INVALID_PARAMETER;
259 }
260
261 MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
262 *AbortReason = NULL;
263
264 if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || Image == NULL) {
265 return EFI_INVALID_PARAMETER;
266 }
267
268 Status = MicrocodeWrite(MicrocodeFmpPrivate, (VOID *)Image, ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason);
269 DEBUG((DEBUG_INFO, "SetImage - LastAttempt Version - 0x%x, Status - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));
270 VarStatus = gRT->SetVariable(
271 MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,
272 &gEfiCallerIdGuid,
273 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
274 sizeof(MicrocodeFmpPrivate->LastAttempt),
275 &MicrocodeFmpPrivate->LastAttempt
276 );
277 DEBUG((DEBUG_INFO, "SetLastAttempt - %r\n", VarStatus));
278
279 if (!EFI_ERROR(Status)) {
280 InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
281 DumpPrivateInfo (MicrocodeFmpPrivate);
282 }
283
284 return Status;
285 }
286
287 /**
288 Checks if the firmware image is valid for the device.
289
290 This function allows firmware update application to validate the firmware image without
291 invoking the SetImage() first.
292
293 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
294 @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
295 The number is between 1 and DescriptorCount.
296 @param[in] Image Points to the new image.
297 @param[in] ImageSize Size of the new image in bytes.
298 @param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides,
299 if available, additional information if the image is invalid.
300
301 @retval EFI_SUCCESS The image was successfully checked.
302 @retval EFI_INVALID_PARAMETER The Image was NULL.
303 @retval EFI_UNSUPPORTED The operation is not supported.
304 @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
305
306 **/
307 EFI_STATUS
308 EFIAPI
309 FmpCheckImage (
310 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
311 IN UINT8 ImageIndex,
312 IN CONST VOID *Image,
313 IN UINTN ImageSize,
314 OUT UINT32 *ImageUpdatable
315 )
316 {
317 return EFI_UNSUPPORTED;
318 }
319
320 /**
321 Returns information about the firmware package.
322
323 This function returns package information.
324
325 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
326 @param[out] PackageVersion A version number that represents all the firmware images in the device.
327 The format is vendor specific and new version must have a greater value
328 than the old version. If PackageVersion is not supported, the value is
329 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version
330 comparison is to be performed using PackageVersionName. A value of
331 0xFFFFFFFD indicates that package version update is in progress.
332 @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing
333 the package version name. The buffer is allocated by this function with
334 AllocatePool(), and it is the caller's responsibility to free it with a
335 call to FreePool().
336 @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of
337 package version name. A value of 0 indicates the device does not support
338 update of package version name. Length is the number of Unicode characters,
339 including the terminating null character.
340 @param[out] AttributesSupported Package attributes that are supported by this device. See 'Package Attribute
341 Definitions' for possible returned values of this parameter. A value of 1
342 indicates the attribute is supported and the current setting value is
343 indicated in AttributesSetting. A value of 0 indicates the attribute is not
344 supported and the current setting value in AttributesSetting is meaningless.
345 @param[out] AttributesSetting Package attributes. See 'Package Attribute Definitions' for possible returned
346 values of this parameter
347
348 @retval EFI_SUCCESS The package information was successfully returned.
349 @retval EFI_UNSUPPORTED The operation is not supported.
350
351 **/
352 EFI_STATUS
353 EFIAPI
354 FmpGetPackageInfo (
355 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
356 OUT UINT32 *PackageVersion,
357 OUT CHAR16 **PackageVersionName,
358 OUT UINT32 *PackageVersionNameMaxLen,
359 OUT UINT64 *AttributesSupported,
360 OUT UINT64 *AttributesSetting
361 )
362 {
363 return EFI_UNSUPPORTED;
364 }
365
366 /**
367 Updates information about the firmware package.
368
369 This function updates package information.
370 This function returns EFI_UNSUPPORTED if the package information is not updatable.
371 VendorCode enables vendor to implement vendor-specific package information update policy.
372 Null if the caller did not specify this policy or use the default policy.
373
374 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
375 @param[in] Image Points to the authentication image.
376 Null if authentication is not required.
377 @param[in] ImageSize Size of the authentication image in bytes.
378 0 if authentication is not required.
379 @param[in] VendorCode This enables vendor to implement vendor-specific firmware
380 image update policy.
381 Null indicates the caller did not specify this policy or use
382 the default policy.
383 @param[in] PackageVersion The new package version.
384 @param[in] PackageVersionName A pointer to the new null-terminated Unicode string representing
385 the package version name.
386 The string length is equal to or less than the value returned in
387 PackageVersionNameMaxLen.
388
389 @retval EFI_SUCCESS The device was successfully updated with the new package
390 information.
391 @retval EFI_INVALID_PARAMETER The PackageVersionName length is longer than the value
392 returned in PackageVersionNameMaxLen.
393 @retval EFI_UNSUPPORTED The operation is not supported.
394 @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
395
396 **/
397 EFI_STATUS
398 EFIAPI
399 FmpSetPackageInfo (
400 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
401 IN CONST VOID *Image,
402 IN UINTN ImageSize,
403 IN CONST VOID *VendorCode,
404 IN UINT32 PackageVersion,
405 IN CONST CHAR16 *PackageVersionName
406 )
407 {
408 return EFI_UNSUPPORTED;
409 }
410
411 /**
412 Sort FIT microcode entries based upon MicrocodeEntryPoint, from low to high.
413
414 @param[in] MicrocodeFmpPrivate private data structure to be initialized.
415
416 **/
417 VOID
418 SortFitMicrocodeInfo (
419 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
420 )
421 {
422 FIT_MICROCODE_INFO *FitMicrocodeEntry;
423 FIT_MICROCODE_INFO *NextFitMicrocodeEntry;
424 FIT_MICROCODE_INFO TempFitMicrocodeEntry;
425 FIT_MICROCODE_INFO *FitMicrocodeEntryEnd;
426
427 FitMicrocodeEntry = MicrocodeFmpPrivate->FitMicrocodeInfo;
428 NextFitMicrocodeEntry = FitMicrocodeEntry + 1;
429 FitMicrocodeEntryEnd = MicrocodeFmpPrivate->FitMicrocodeInfo + MicrocodeFmpPrivate->FitMicrocodeEntryCount;
430 while (FitMicrocodeEntry < FitMicrocodeEntryEnd) {
431 while (NextFitMicrocodeEntry < FitMicrocodeEntryEnd) {
432 if (FitMicrocodeEntry->MicrocodeEntryPoint > NextFitMicrocodeEntry->MicrocodeEntryPoint) {
433 CopyMem (&TempFitMicrocodeEntry, FitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));
434 CopyMem (FitMicrocodeEntry, NextFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));
435 CopyMem (NextFitMicrocodeEntry, &TempFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));
436 }
437
438 NextFitMicrocodeEntry = NextFitMicrocodeEntry + 1;
439 }
440
441 FitMicrocodeEntry = FitMicrocodeEntry + 1;
442 NextFitMicrocodeEntry = FitMicrocodeEntry + 1;
443 }
444 }
445
446 /**
447 Initialize FIT microcode information.
448
449 @param[in] MicrocodeFmpPrivate private data structure to be initialized.
450
451 @return EFI_SUCCESS FIT microcode information is initialized.
452 @return EFI_OUT_OF_RESOURCES No enough resource for the initialization.
453 @return EFI_DEVICE_ERROR There is something wrong in FIT microcode entry.
454 **/
455 EFI_STATUS
456 InitializeFitMicrocodeInfo (
457 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
458 )
459 {
460 UINT64 FitPointer;
461 FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
462 UINT32 EntryNum;
463 UINT32 MicrocodeEntryNum;
464 UINT32 Index;
465 UINTN Address;
466 VOID *MicrocodePatchAddress;
467 UINTN MicrocodePatchRegionSize;
468 FIT_MICROCODE_INFO *FitMicrocodeInfo;
469 FIT_MICROCODE_INFO *FitMicrocodeInfoNext;
470 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
471 CPU_MICROCODE_HEADER *MicrocodeEntryPointNext;
472 UINTN FitMicrocodeIndex;
473 MICROCODE_INFO *MicrocodeInfo;
474 UINTN MicrocodeIndex;
475
476 if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {
477 FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);
478 MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;
479 MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;
480 }
481
482 FitPointer = *(UINT64 *) (UINTN) FIT_POINTER_ADDRESS;
483 if ((FitPointer == 0) ||
484 (FitPointer == 0xFFFFFFFFFFFFFFFF) ||
485 (FitPointer == 0xEEEEEEEEEEEEEEEE)) {
486 //
487 // No FIT table.
488 //
489 return EFI_SUCCESS;
490 }
491 FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *) (UINTN) FitPointer;
492 if ((FitEntry[0].Type != FIT_TYPE_00_HEADER) ||
493 (FitEntry[0].Address != FIT_TYPE_00_SIGNATURE)) {
494 //
495 // Invalid FIT table, treat it as no FIT table.
496 //
497 return EFI_SUCCESS;
498 }
499
500 EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
501
502 //
503 // Calculate microcode entry number.
504 //
505 MicrocodeEntryNum = 0;
506 for (Index = 0; Index < EntryNum; Index++) {
507 if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {
508 MicrocodeEntryNum++;
509 }
510 }
511 if (MicrocodeEntryNum == 0) {
512 //
513 // No FIT microcode entry.
514 //
515 return EFI_SUCCESS;
516 }
517
518 //
519 // Allocate buffer.
520 //
521 MicrocodeFmpPrivate->FitMicrocodeInfo = AllocateZeroPool (MicrocodeEntryNum * sizeof (FIT_MICROCODE_INFO));
522 if (MicrocodeFmpPrivate->FitMicrocodeInfo == NULL) {
523 return EFI_OUT_OF_RESOURCES;
524 }
525
526 MicrocodeFmpPrivate->FitMicrocodeEntryCount = MicrocodeEntryNum;
527
528 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
529 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
530
531 //
532 // Collect microcode entry info.
533 //
534 MicrocodeEntryNum = 0;
535 for (Index = 0; Index < EntryNum; Index++) {
536 if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {
537 Address = (UINTN) FitEntry[Index].Address;
538 if ((Address < (UINTN) MicrocodePatchAddress) ||
539 (Address >= ((UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize))) {
540 DEBUG ((
541 DEBUG_ERROR,
542 "InitializeFitMicrocodeInfo - Address (0x%x) is not in Microcode Region\n",
543 Address
544 ));
545 goto ErrorExit;
546 }
547 FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[MicrocodeEntryNum];
548 FitMicrocodeInfo->MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) Address;
549 if ((*(UINT32 *) Address) == 0xFFFFFFFF) {
550 //
551 // It is the empty slot as long as the first dword is 0xFFFF_FFFF.
552 //
553 FitMicrocodeInfo->Empty = TRUE;
554 } else {
555 FitMicrocodeInfo->Empty = FALSE;
556 }
557 MicrocodeEntryNum++;
558 }
559 }
560
561 //
562 // Every microcode should have a FIT microcode entry.
563 //
564 for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {
565 MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex];
566 for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount; FitMicrocodeIndex++) {
567 FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];
568 if (MicrocodeInfo->MicrocodeEntryPoint == FitMicrocodeInfo->MicrocodeEntryPoint) {
569 FitMicrocodeInfo->TotalSize = MicrocodeInfo->TotalSize;
570 FitMicrocodeInfo->InUse = MicrocodeInfo->InUse;
571 break;
572 }
573 }
574 if (FitMicrocodeIndex >= MicrocodeFmpPrivate->FitMicrocodeEntryCount) {
575 DEBUG ((
576 DEBUG_ERROR,
577 "InitializeFitMicrocodeInfo - There is no FIT microcode entry for Microcode (0x%x)\n",
578 MicrocodeInfo->MicrocodeEntryPoint
579 ));
580 goto ErrorExit;
581 }
582 }
583
584 SortFitMicrocodeInfo (MicrocodeFmpPrivate);
585
586 //
587 // Check overlap.
588 //
589 for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1; FitMicrocodeIndex++) {
590 FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];
591 MicrocodeEntryPoint = FitMicrocodeInfo->MicrocodeEntryPoint;
592 FitMicrocodeInfoNext = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex + 1];
593 MicrocodeEntryPointNext = FitMicrocodeInfoNext->MicrocodeEntryPoint;
594 if ((MicrocodeEntryPoint >= MicrocodeEntryPointNext) ||
595 ((FitMicrocodeInfo->TotalSize != 0) &&
596 ((UINTN) MicrocodeEntryPoint + FitMicrocodeInfo->TotalSize) >
597 (UINTN) MicrocodeEntryPointNext)) {
598 DEBUG ((
599 DEBUG_ERROR,
600 "InitializeFitMicrocodeInfo - There is overlap between FIT microcode entries (0x%x 0x%x)\n",
601 MicrocodeEntryPoint,
602 MicrocodeEntryPointNext
603 ));
604 goto ErrorExit;
605 }
606 }
607
608 return EFI_SUCCESS;
609
610 ErrorExit:
611 FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);
612 MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;
613 MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;
614 return EFI_DEVICE_ERROR;
615 }
616
617 /**
618 Initialize Processor Microcode Index.
619
620 @param[in] MicrocodeFmpPrivate private data structure to be initialized.
621 **/
622 VOID
623 InitializedProcessorMicrocodeIndex (
624 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
625 )
626 {
627 UINTN CpuIndex;
628 UINTN MicrocodeIndex;
629 UINTN TargetCpuIndex;
630 UINT32 AttemptStatus;
631 EFI_STATUS Status;
632
633 for (CpuIndex = 0; CpuIndex < MicrocodeFmpPrivate->ProcessorCount; CpuIndex++) {
634 if (MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex != (UINTN)-1) {
635 continue;
636 }
637 for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {
638 if (!MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].InUse) {
639 continue;
640 }
641 TargetCpuIndex = CpuIndex;
642 Status = VerifyMicrocode(
643 MicrocodeFmpPrivate,
644 MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].MicrocodeEntryPoint,
645 MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].TotalSize,
646 FALSE,
647 &AttemptStatus,
648 NULL,
649 &TargetCpuIndex
650 );
651 if (!EFI_ERROR(Status)) {
652 MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex = MicrocodeIndex;
653 }
654 }
655 }
656 }
657
658 /**
659 Initialize Microcode Descriptor.
660
661 @param[in] MicrocodeFmpPrivate private data structure to be initialized.
662
663 @return EFI_SUCCESS Microcode Descriptor is initialized.
664 @return EFI_OUT_OF_RESOURCES No enough resource for the initialization.
665 **/
666 EFI_STATUS
667 InitializeMicrocodeDescriptor (
668 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
669 )
670 {
671 EFI_STATUS Status;
672 UINT8 CurrentMicrocodeCount;
673
674 CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, 0, NULL, NULL);
675
676 if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) {
677 if (MicrocodeFmpPrivate->ImageDescriptor != NULL) {
678 FreePool(MicrocodeFmpPrivate->ImageDescriptor);
679 MicrocodeFmpPrivate->ImageDescriptor = NULL;
680 }
681 if (MicrocodeFmpPrivate->MicrocodeInfo != NULL) {
682 FreePool(MicrocodeFmpPrivate->MicrocodeInfo);
683 MicrocodeFmpPrivate->MicrocodeInfo = NULL;
684 }
685 } else {
686 ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR));
687 ZeroMem(MicrocodeFmpPrivate->MicrocodeInfo, MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
688 }
689
690 MicrocodeFmpPrivate->DescriptorCount = CurrentMicrocodeCount;
691
692 if (MicrocodeFmpPrivate->ImageDescriptor == NULL) {
693 MicrocodeFmpPrivate->ImageDescriptor = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR));
694 if (MicrocodeFmpPrivate->ImageDescriptor == NULL) {
695 return EFI_OUT_OF_RESOURCES;
696 }
697 }
698 if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
699 MicrocodeFmpPrivate->MicrocodeInfo = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
700 if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
701 FreePool (MicrocodeFmpPrivate->ImageDescriptor);
702 return EFI_OUT_OF_RESOURCES;
703 }
704 }
705
706 CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, MicrocodeFmpPrivate->DescriptorCount, MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->MicrocodeInfo);
707 ASSERT(CurrentMicrocodeCount == MicrocodeFmpPrivate->DescriptorCount);
708
709 InitializedProcessorMicrocodeIndex (MicrocodeFmpPrivate);
710
711 Status = InitializeFitMicrocodeInfo (MicrocodeFmpPrivate);
712 if (EFI_ERROR(Status)) {
713 FreePool (MicrocodeFmpPrivate->ImageDescriptor);
714 FreePool (MicrocodeFmpPrivate->MicrocodeInfo);
715 DEBUG((DEBUG_ERROR, "InitializeFitMicrocodeInfo - %r\n", Status));
716 return Status;
717 }
718
719 return EFI_SUCCESS;
720 }
721
722 /**
723 Initialize MicrocodeFmpDriver multiprocessor information.
724
725 @param[in] MicrocodeFmpPrivate private data structure to be initialized.
726
727 @return EFI_SUCCESS Processor information is initialized.
728 @return EFI_OUT_OF_RESOURCES No enough resource for the initialization.
729 **/
730 EFI_STATUS
731 InitializeProcessorInfo (
732 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
733 )
734 {
735 EFI_STATUS Status;
736 EFI_MP_SERVICES_PROTOCOL *MpService;
737 UINTN NumberOfProcessors;
738 UINTN NumberOfEnabledProcessors;
739 UINTN Index;
740 UINTN BspIndex;
741
742 Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService);
743 ASSERT_EFI_ERROR(Status);
744
745 MicrocodeFmpPrivate->MpService = MpService;
746 MicrocodeFmpPrivate->ProcessorCount = 0;
747 MicrocodeFmpPrivate->ProcessorInfo = NULL;
748
749 Status = MpService->GetNumberOfProcessors (MpService, &NumberOfProcessors, &NumberOfEnabledProcessors);
750 ASSERT_EFI_ERROR(Status);
751 MicrocodeFmpPrivate->ProcessorCount = NumberOfProcessors;
752
753 Status = MpService->WhoAmI (MpService, &BspIndex);
754 ASSERT_EFI_ERROR(Status);
755 MicrocodeFmpPrivate->BspIndex = BspIndex;
756
757 MicrocodeFmpPrivate->ProcessorInfo = AllocateZeroPool (sizeof(PROCESSOR_INFO) * MicrocodeFmpPrivate->ProcessorCount);
758 if (MicrocodeFmpPrivate->ProcessorInfo == NULL) {
759 return EFI_OUT_OF_RESOURCES;
760 }
761
762 for (Index = 0; Index < NumberOfProcessors; Index++) {
763 MicrocodeFmpPrivate->ProcessorInfo[Index].CpuIndex = Index;
764 MicrocodeFmpPrivate->ProcessorInfo[Index].MicrocodeIndex = (UINTN)-1;
765 if (Index == BspIndex) {
766 CollectProcessorInfo (&MicrocodeFmpPrivate->ProcessorInfo[Index]);
767 } else {
768 Status = MpService->StartupThisAP (
769 MpService,
770 CollectProcessorInfo,
771 Index,
772 NULL,
773 0,
774 &MicrocodeFmpPrivate->ProcessorInfo[Index],
775 NULL
776 );
777 ASSERT_EFI_ERROR(Status);
778 }
779 }
780
781 return EFI_SUCCESS;
782 }
783
784 /**
785 Dump private information.
786
787 @param[in] MicrocodeFmpPrivate private data structure.
788 **/
789 VOID
790 DumpPrivateInfo (
791 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
792 )
793 {
794 UINTN Index;
795 PROCESSOR_INFO *ProcessorInfo;
796 MICROCODE_INFO *MicrocodeInfo;
797 EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor;
798 FIT_MICROCODE_INFO *FitMicrocodeInfo;
799
800 DEBUG ((DEBUG_INFO, "ProcessorInfo:\n"));
801 DEBUG ((DEBUG_INFO, " ProcessorCount - 0x%x\n", MicrocodeFmpPrivate->ProcessorCount));
802 DEBUG ((DEBUG_INFO, " BspIndex - 0x%x\n", MicrocodeFmpPrivate->BspIndex));
803
804 ProcessorInfo = MicrocodeFmpPrivate->ProcessorInfo;
805 for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
806 DEBUG ((
807 DEBUG_INFO,
808 " ProcessorInfo[0x%x] - 0x%08x, 0x%02x, 0x%08x, (0x%x)\n",
809 ProcessorInfo[Index].CpuIndex,
810 ProcessorInfo[Index].ProcessorSignature,
811 ProcessorInfo[Index].PlatformId,
812 ProcessorInfo[Index].MicrocodeRevision,
813 ProcessorInfo[Index].MicrocodeIndex
814 ));
815 }
816
817 DEBUG ((DEBUG_INFO, "MicrocodeInfo:\n"));
818 MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
819 DEBUG ((DEBUG_INFO, " MicrocodeRegion - 0x%x - 0x%x\n", MicrocodeFmpPrivate->MicrocodePatchAddress, MicrocodeFmpPrivate->MicrocodePatchRegionSize));
820 DEBUG ((DEBUG_INFO, " MicrocodeCount - 0x%x\n", MicrocodeFmpPrivate->DescriptorCount));
821 for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
822 DEBUG ((
823 DEBUG_INFO,
824 " MicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x)\n",
825 Index,
826 MicrocodeInfo[Index].MicrocodeEntryPoint,
827 MicrocodeInfo[Index].TotalSize,
828 MicrocodeInfo[Index].InUse
829 ));
830 }
831
832 ImageDescriptor = MicrocodeFmpPrivate->ImageDescriptor;
833 DEBUG ((DEBUG_VERBOSE, "ImageDescriptor:\n"));
834 for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
835 DEBUG((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
836 DEBUG((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", ImageDescriptor[Index].ImageIndex));
837 DEBUG((DEBUG_VERBOSE, " ImageTypeId - %g\n", &ImageDescriptor[Index].ImageTypeId));
838 DEBUG((DEBUG_VERBOSE, " ImageId - 0x%lx\n", ImageDescriptor[Index].ImageId));
839 DEBUG((DEBUG_VERBOSE, " ImageIdName - %s\n", ImageDescriptor[Index].ImageIdName));
840 DEBUG((DEBUG_VERBOSE, " Version - 0x%x\n", ImageDescriptor[Index].Version));
841 DEBUG((DEBUG_VERBOSE, " VersionName - %s\n", ImageDescriptor[Index].VersionName));
842 DEBUG((DEBUG_VERBOSE, " Size - 0x%x\n", ImageDescriptor[Index].Size));
843 DEBUG((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", ImageDescriptor[Index].AttributesSupported));
844 DEBUG((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", ImageDescriptor[Index].AttributesSetting));
845 DEBUG((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", ImageDescriptor[Index].Compatibilities));
846 DEBUG((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", ImageDescriptor[Index].LowestSupportedImageVersion));
847 DEBUG((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", ImageDescriptor[Index].LastAttemptVersion));
848 DEBUG((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", ImageDescriptor[Index].LastAttemptStatus));
849 DEBUG((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", ImageDescriptor[Index].HardwareInstance));
850 }
851
852 if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {
853 DEBUG ((DEBUG_INFO, "FitMicrocodeInfo:\n"));
854 FitMicrocodeInfo = MicrocodeFmpPrivate->FitMicrocodeInfo;
855 DEBUG ((DEBUG_INFO, " FitMicrocodeEntryCount - 0x%x\n", MicrocodeFmpPrivate->FitMicrocodeEntryCount));
856 for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {
857 DEBUG ((
858 DEBUG_INFO,
859 " FitMicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x, 0x%x)\n",
860 Index,
861 FitMicrocodeInfo[Index].MicrocodeEntryPoint,
862 FitMicrocodeInfo[Index].TotalSize,
863 FitMicrocodeInfo[Index].InUse,
864 FitMicrocodeInfo[Index].Empty
865 ));
866 }
867 }
868 }
869
870 /**
871 Initialize MicrocodeFmpDriver private data structure.
872
873 @param[in] MicrocodeFmpPrivate private data structure to be initialized.
874
875 @return EFI_SUCCESS private data is initialized.
876 **/
877 EFI_STATUS
878 InitializePrivateData (
879 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
880 )
881 {
882 EFI_STATUS Status;
883 EFI_STATUS VarStatus;
884 UINTN VarSize;
885 BOOLEAN Result;
886
887 MicrocodeFmpPrivate->Signature = MICROCODE_FMP_PRIVATE_DATA_SIGNATURE;
888 MicrocodeFmpPrivate->Handle = NULL;
889 CopyMem(&MicrocodeFmpPrivate->Fmp, &mFirmwareManagementProtocol, sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL));
890
891 MicrocodeFmpPrivate->PackageVersion = 0x1;
892 MicrocodeFmpPrivate->PackageVersionName = L"Microcode";
893
894 MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion = 0x0;
895 MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus = 0x0;
896 VarSize = sizeof(MicrocodeFmpPrivate->LastAttempt);
897 VarStatus = gRT->GetVariable(
898 MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,
899 &gEfiCallerIdGuid,
900 NULL,
901 &VarSize,
902 &MicrocodeFmpPrivate->LastAttempt
903 );
904 DEBUG((DEBUG_INFO, "GetLastAttempt - %r\n", VarStatus));
905 DEBUG((DEBUG_INFO, "GetLastAttempt Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));
906
907 Result = GetMicrocodeRegion(&MicrocodeFmpPrivate->MicrocodePatchAddress, &MicrocodeFmpPrivate->MicrocodePatchRegionSize);
908 if (!Result) {
909 DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n"));
910 return EFI_NOT_FOUND;
911 }
912
913 Status = InitializeProcessorInfo (MicrocodeFmpPrivate);
914 if (EFI_ERROR(Status)) {
915 DEBUG((DEBUG_ERROR, "InitializeProcessorInfo - %r\n", Status));
916 return Status;
917 }
918
919 Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
920 if (EFI_ERROR(Status)) {
921 FreePool (MicrocodeFmpPrivate->ProcessorInfo);
922 DEBUG((DEBUG_ERROR, "InitializeMicrocodeDescriptor - %r\n", Status));
923 return Status;
924 }
925
926 DumpPrivateInfo (MicrocodeFmpPrivate);
927
928 return Status;
929 }
930
931 /**
932 Microcode FMP module entrypoint
933
934 @param[in] ImageHandle The firmware allocated handle for the EFI image.
935 @param[in] SystemTable A pointer to the EFI System Table.
936
937 @return EFI_SUCCESS Microcode FMP module is initialized.
938 **/
939 EFI_STATUS
940 EFIAPI
941 MicrocodeFmpMain (
942 IN EFI_HANDLE ImageHandle,
943 IN EFI_SYSTEM_TABLE *SystemTable
944 )
945 {
946 EFI_STATUS Status;
947
948 //
949 // Initialize MicrocodeFmpPrivateData
950 //
951 mMicrocodeFmpPrivate = AllocateZeroPool (sizeof(MICROCODE_FMP_PRIVATE_DATA));
952 if (mMicrocodeFmpPrivate == NULL) {
953 return EFI_OUT_OF_RESOURCES;
954 }
955
956 Status = InitializePrivateData(mMicrocodeFmpPrivate);
957 if (EFI_ERROR(Status)) {
958 FreePool(mMicrocodeFmpPrivate);
959 mMicrocodeFmpPrivate = NULL;
960 return Status;
961 }
962
963 //
964 // Install FMP protocol.
965 //
966 Status = gBS->InstallProtocolInterface (
967 &mMicrocodeFmpPrivate->Handle,
968 &gEfiFirmwareManagementProtocolGuid,
969 EFI_NATIVE_INTERFACE,
970 &mMicrocodeFmpPrivate->Fmp
971 );
972 if (EFI_ERROR (Status)) {
973 FreePool(mMicrocodeFmpPrivate);
974 mMicrocodeFmpPrivate = NULL;
975 return Status;
976 }
977
978 return Status;
979 }