1 /** @file
2   Produces a Firmware Management Protocol that supports updates to a firmware
3   image stored in a firmware device with platform and firmware device specific
4   information provided through PCDs and libraries.
5 
6   Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
7   Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
8 
9   SPDX-License-Identifier: BSD-2-Clause-Patent
10 
11 **/
12 
13 #include <PiDxe.h>
14 #include <Library/DebugLib.h>
15 #include <Library/BaseLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/UefiLib.h>
20 #include <Library/FmpAuthenticationLib.h>
21 #include <Library/FmpDeviceLib.h>
22 #include <Library/FmpPayloadHeaderLib.h>
23 #include <Library/CapsuleUpdatePolicyLib.h>
24 #include <Protocol/FirmwareManagement.h>
25 #include <Protocol/FirmwareManagementProgress.h>
26 #include <Guid/SystemResourceTable.h>
27 #include <Guid/EventGroup.h>
28 #include "VariableSupport.h"
29 
30 #define VERSION_STRING_NOT_SUPPORTED  L"VERSION STRING NOT SUPPORTED"
31 #define VERSION_STRING_NOT_AVAILABLE  L"VERSION STRING NOT AVAILABLE"
32 
33 /**
34   Check to see if any of the keys in PcdFmpDevicePkcs7CertBufferXdr matches
35   the test key.  PcdFmpDeviceTestKeySha256Digest contains the SHA256 hash of
36   the test key.  For each key in PcdFmpDevicePkcs7CertBufferXdr, compute the
37   SHA256 hash and compare it to PcdFmpDeviceTestKeySha256Digest.  If the
38   SHA256 hash matches or there is then error computing the SHA256 hash, then
39   set PcdTestKeyUsed to TRUE.  Skip this check if PcdTestKeyUsed is already
40   TRUE or PcdFmpDeviceTestKeySha256Digest is not exactly SHA256_DIGEST_SIZE
41   bytes.
42 **/
43 VOID
44 DetectTestKey (
45   VOID
46   );
47 
48 ///
49 /// FILE_GUID from FmpDxe.inf.  When FmpDxe.inf is used in a platform, the
50 /// FILE_GUID must always be overridden in the <Defines> section to provide
51 /// the ESRT GUID value associated with the updatable firmware image.  A
52 /// check is made in this module's driver entry point to verify that a
53 /// new FILE_GUID value has been defined.
54 ///
55 const EFI_GUID  mDefaultModuleFileGuid = {
56   0x78ef0a56, 0x1cf0, 0x4535, { 0xb5, 0xda, 0xf6, 0xfd, 0x2f, 0x40, 0x5a, 0x11 }
57 };
58 
59 EFI_FIRMWARE_IMAGE_DESCRIPTOR  mDesc;
60 BOOLEAN                        mDescriptorPopulated     = FALSE;
61 BOOLEAN                        mRuntimeVersionSupported = TRUE;
62 BOOLEAN                        mFmpInstalled            = FALSE;
63 
64 ///
65 /// Function pointer to progress function
66 ///
67 EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  mProgressFunc      = NULL;
68 BOOLEAN                                        mProgressSupported = FALSE;
69 
70 CHAR16  *mImageIdName = NULL;
71 UINT64  mImageId      = 0x1;
72 CHAR16  *mVersionName = NULL;
73 
74 EFI_EVENT  mFmpDeviceLockEvent;
75 //
76 // Indicates if an attempt has been made to lock a
77 // FLASH storage device by calling FmpDeviceLock().
78 // A FLASH storage device may not support being locked,
79 // so this variable is set to TRUE even if FmpDeviceLock()
80 // returns an error.
81 //
82 BOOLEAN    mFmpDeviceLocked = FALSE;
83 
84 /**
85   Callback function to report the process of the firmware updating.
86 
87   Wrap the caller's version in this so that progress from the device lib is
88   within the expected range.  Convert device lib 0% - 100% to 6% - 98%.
89 
90   FmpDxe        1% -   5%  for validation
91   FmpDeviceLib  6% -  98%  for flashing/update
92   FmpDxe       99% - 100%  finish
93 
94   @param[in] Completion  A value between 1 and 100 indicating the current
95                          completion progress of the firmware update. Completion
96                          progress is reported as from 1 to 100 percent. A value
97                          of 0 is used by the driver to indicate that progress
98                          reporting is not supported.
99 
100   @retval  EFI_SUCCESS      The progress was updated.
101   @retval  EFI_UNSUPPORTED  Updating progress is not supported.
102 
103 **/
104 EFI_STATUS
105 EFIAPI
FmpDxeProgress(IN UINTN Completion)106 FmpDxeProgress (
107   IN UINTN  Completion
108   )
109 {
110   EFI_STATUS Status;
111 
112   Status = EFI_UNSUPPORTED;
113 
114   if (!mProgressSupported) {
115     return Status;
116   }
117 
118   if (mProgressFunc == NULL) {
119     return Status;
120   }
121 
122   //
123   // Reserve 6% - 98% for the FmpDeviceLib.  Call the real progress function.
124   //
125   Status = mProgressFunc (((Completion * 92) / 100) + 6);
126 
127   if (Status == EFI_UNSUPPORTED) {
128     mProgressSupported = FALSE;
129     mProgressFunc = NULL;
130   }
131 
132   return Status;
133 }
134 
135 /**
136   Returns a pointer to the ImageTypeId GUID value.  An attempt is made to get
137   the GUID value from the FmpDeviceLib. If the FmpDeviceLib does not provide
138   a GUID value, then gEfiCallerIdGuid is returned.
139 
140   @return  The ImageTypeId GUID
141 
142 **/
143 EFI_GUID *
GetImageTypeIdGuid(VOID)144 GetImageTypeIdGuid (
145   VOID
146   )
147 {
148   EFI_STATUS  Status;
149   EFI_GUID    *FmpDeviceLibGuid;
150 
151   FmpDeviceLibGuid = NULL;
152   Status = FmpDeviceGetImageTypeIdGuidPtr (&FmpDeviceLibGuid);
153   if (EFI_ERROR (Status)) {
154     if (Status != EFI_UNSUPPORTED) {
155       DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid error %r\n", Status));
156     }
157     return &gEfiCallerIdGuid;
158   }
159   if (FmpDeviceLibGuid == NULL) {
160     DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid GUID\n"));
161     return &gEfiCallerIdGuid;
162   }
163   return FmpDeviceLibGuid;
164 }
165 
166 /**
167   Returns a pointer to the Null-terminated Unicode ImageIdName string.
168 
169   @return  Null-terminated Unicode ImageIdName string.
170 
171 **/
172 CHAR16 *
GetImageTypeNameString(VOID)173 GetImageTypeNameString (
174   VOID
175   )
176 {
177   return mImageIdName;
178 }
179 
180 /**
181   Lowest supported version is a combo of three parts.
182   1. Check if the device lib has a lowest supported version
183   2. Check if we have a variable for lowest supported version (this will be updated with each capsule applied)
184   3. Check Fixed at build PCD
185 
186   Take the largest value
187 
188 **/
189 UINT32
GetLowestSupportedVersion(VOID)190 GetLowestSupportedVersion (
191   VOID
192   )
193 {
194   EFI_STATUS  Status;
195   UINT32      DeviceLibLowestSupportedVersion;
196   UINT32      VariableLowestSupportedVersion;
197   UINT32      ReturnLsv;
198 
199   //
200   // Get the LowestSupportedVersion.
201   //
202 
203   if (!IsLowestSupportedVersionCheckRequired ()) {
204     //
205     // Any Version can pass the 0 LowestSupportedVersion check.
206     //
207     return 0;
208   }
209 
210   ReturnLsv = PcdGet32 (PcdFmpDeviceBuildTimeLowestSupportedVersion);
211 
212   //
213   // Check the FmpDeviceLib
214   //
215   DeviceLibLowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;
216   Status = FmpDeviceGetLowestSupportedVersion (&DeviceLibLowestSupportedVersion);
217   if (EFI_ERROR (Status)) {
218     DeviceLibLowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;
219   }
220 
221   if (DeviceLibLowestSupportedVersion > ReturnLsv) {
222     ReturnLsv = DeviceLibLowestSupportedVersion;
223   }
224 
225   //
226   // Check the lowest supported version UEFI variable for this device
227   //
228   VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable();
229   if (VariableLowestSupportedVersion > ReturnLsv) {
230     ReturnLsv = VariableLowestSupportedVersion;
231   }
232 
233   //
234   // Return the largest value
235   //
236   return ReturnLsv;
237 }
238 
239 /**
240   Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the module global
241   variable mDesc.
242 
243 **/
244 VOID
PopulateDescriptor(VOID)245 PopulateDescriptor (
246   VOID
247   )
248 {
249   EFI_STATUS  Status;
250 
251   mDesc.ImageIndex = 1;
252   CopyGuid (&mDesc.ImageTypeId, GetImageTypeIdGuid());
253   mDesc.ImageId = mImageId;
254   mDesc.ImageIdName = GetImageTypeNameString();
255 
256   //
257   // Get the version.  Some devices don't support getting the firmware version
258   // at runtime.  If FmpDeviceLib does not support returning a version, then
259   // it is stored in a UEFI variable.
260   //
261   Status = FmpDeviceGetVersion (&mDesc.Version);
262   if (Status == EFI_UNSUPPORTED) {
263     mRuntimeVersionSupported = FALSE;
264     mDesc.Version = GetVersionFromVariable();
265   } else if (EFI_ERROR (Status)) {
266     //
267     // Unexpected error.   Use default version.
268     //
269     DEBUG ((DEBUG_ERROR, "FmpDxe: GetVersion() from FmpDeviceLib (%s) returned %r\n", GetImageTypeNameString(), Status));
270     mDesc.Version = DEFAULT_VERSION;
271   }
272 
273   //
274   // Free the current version name.  Shouldn't really happen but this populate
275   // function could be called multiple times (to refresh).
276   //
277   if (mVersionName != NULL) {
278     FreePool (mVersionName);
279     mVersionName = NULL;
280   }
281 
282   //
283   // Attempt to get the version string from the FmpDeviceLib
284   //
285   Status = FmpDeviceGetVersionString (&mVersionName);
286   if (Status == EFI_UNSUPPORTED) {
287     DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() unsupported in FmpDeviceLib.\n"));
288     mVersionName = AllocateCopyPool (
289                      sizeof (VERSION_STRING_NOT_SUPPORTED),
290                      VERSION_STRING_NOT_SUPPORTED
291                      );
292   } else if (EFI_ERROR (Status)) {
293     DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() not available in FmpDeviceLib.\n"));
294     mVersionName = AllocateCopyPool (
295                      sizeof (VERSION_STRING_NOT_AVAILABLE),
296                      VERSION_STRING_NOT_AVAILABLE
297                      );
298   }
299 
300   mDesc.VersionName = mVersionName;
301 
302   mDesc.LowestSupportedImageVersion = GetLowestSupportedVersion();
303 
304   //
305   // Get attributes from the FmpDeviceLib
306   //
307   FmpDeviceGetAttributes (&mDesc.AttributesSupported, &mDesc.AttributesSetting);
308 
309   //
310   // Force set the updatable bits in the attributes;
311   //
312   mDesc.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
313   mDesc.AttributesSetting   |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
314 
315   //
316   // Force set the authentication bits in the attributes;
317   //
318   mDesc.AttributesSupported |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
319   mDesc.AttributesSetting   |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
320 
321   mDesc.Compatibilities = 0;
322 
323   //
324   // Get the size of the firmware image from the FmpDeviceLib
325   //
326   Status = FmpDeviceGetSize (&mDesc.Size);
327   if (EFI_ERROR (Status)) {
328     mDesc.Size = 0;
329   }
330 
331   mDesc.LastAttemptVersion = GetLastAttemptVersionFromVariable ();
332   mDesc.LastAttemptStatus  = GetLastAttemptStatusFromVariable ();
333 
334   mDescriptorPopulated = TRUE;
335 }
336 
337 /**
338   Returns information about the current firmware image(s) of the device.
339 
340   This function allows a copy of the current firmware image to be created and saved.
341   The saved copy could later been used, for example, in firmware image recovery or rollback.
342 
343   @param[in]      This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
344   @param[in, out] ImageInfoSize      A pointer to the size, in bytes, of the ImageInfo buffer.
345                                      On input, this is the size of the buffer allocated by the caller.
346                                      On output, it is the size of the buffer returned by the firmware
347                                      if the buffer was large enough, or the size of the buffer needed
348                                      to contain the image(s) information if the buffer was too small.
349   @param[in, out] ImageInfo          A pointer to the buffer in which firmware places the current image(s)
350                                      information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
351   @param[out]     DescriptorVersion  A pointer to the location in which firmware returns the version number
352                                      associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
353   @param[out]     DescriptorCount    A pointer to the location in which firmware returns the number of
354                                      descriptors or firmware images within this device.
355   @param[out]     DescriptorSize     A pointer to the location in which firmware returns the size, in bytes,
356                                      of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
357   @param[out]     PackageVersion     A version number that represents all the firmware images in the device.
358                                      The format is vendor specific and new version must have a greater value
359                                      than the old version. If PackageVersion is not supported, the value is
360                                      0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison
361                                      is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates
362                                      that package version update is in progress.
363   @param[out]     PackageVersionName A pointer to a pointer to a null-terminated string representing the
364                                      package version name. The buffer is allocated by this function with
365                                      AllocatePool(), and it is the caller's responsibility to free it with a call
366                                      to FreePool().
367 
368   @retval EFI_SUCCESS                The device was successfully updated with the new image.
369   @retval EFI_BUFFER_TOO_SMALL       The ImageInfo buffer was too small. The current buffer size
370                                      needed to hold the image(s) information is returned in ImageInfoSize.
371   @retval EFI_INVALID_PARAMETER      ImageInfoSize is NULL.
372   @retval EFI_DEVICE_ERROR           Valid information could not be returned. Possible corrupted image.
373 
374 **/
375 EFI_STATUS
376 EFIAPI
GetTheImageInfo(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This,IN OUT UINTN * ImageInfoSize,IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR * ImageInfo,OUT UINT32 * DescriptorVersion,OUT UINT8 * DescriptorCount,OUT UINTN * DescriptorSize,OUT UINT32 * PackageVersion,OUT CHAR16 ** PackageVersionName)377 GetTheImageInfo (
378   IN     EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
379   IN OUT UINTN                             *ImageInfoSize,
380   IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR     *ImageInfo,
381   OUT    UINT32                            *DescriptorVersion,
382   OUT    UINT8                             *DescriptorCount,
383   OUT    UINTN                             *DescriptorSize,
384   OUT    UINT32                            *PackageVersion,
385   OUT    CHAR16                            **PackageVersionName
386   )
387 {
388   EFI_STATUS Status;
389 
390   Status = EFI_SUCCESS;
391 
392   //
393   // Check for valid pointer
394   //
395   if (ImageInfoSize == NULL) {
396     DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - ImageInfoSize is NULL.\n"));
397     Status = EFI_INVALID_PARAMETER;
398     goto cleanup;
399   }
400 
401   //
402   // Check the buffer size
403   // NOTE: Check this first so caller can get the necessary memory size it must allocate.
404   //
405   if (*ImageInfoSize < (sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR))) {
406     *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
407     DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImageInfo() - ImageInfoSize is to small.\n"));
408     Status = EFI_BUFFER_TOO_SMALL;
409     goto cleanup;
410   }
411 
412   //
413   // Confirm that buffer isn't null
414   //
415   if ( (ImageInfo == NULL) || (DescriptorVersion == NULL) || (DescriptorCount == NULL) || (DescriptorSize == NULL)
416        || (PackageVersion == NULL)) {
417     DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - Pointer Parameter is NULL.\n"));
418     Status = EFI_INVALID_PARAMETER;
419     goto cleanup;
420   }
421 
422   //
423   // Set the size to whatever we need
424   //
425   *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
426 
427 
428   if (!mDescriptorPopulated) {
429     PopulateDescriptor();
430   }
431 
432   //
433   // Copy the image descriptor
434   //
435   CopyMem (ImageInfo, &mDesc, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR));
436 
437   *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
438   *DescriptorCount = 1;
439   *DescriptorSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
440   //
441   // means unsupported
442   //
443   *PackageVersion = 0xFFFFFFFF;
444 
445   //
446   // Do not update PackageVersionName since it is not supported in this instance.
447   //
448 
449 cleanup:
450 
451   return Status;
452 }
453 
454 /**
455   Retrieves a copy of the current firmware image of the device.
456 
457   This function allows a copy of the current firmware image to be created and saved.
458   The saved copy could later been used, for example, in firmware image recovery or rollback.
459 
460   @param[in]      This           A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
461   @param[in]      ImageIndex     A unique number identifying the firmware image(s) within the device.
462                                  The number is between 1 and DescriptorCount.
463   @param[in, out] Image          Points to the buffer where the current image is copied to.
464   @param[in, out] ImageSize      On entry, points to the size of the buffer pointed to by Image, in bytes.
465                                  On return, points to the length of the image, in bytes.
466 
467   @retval EFI_SUCCESS            The device was successfully updated with the new image.
468   @retval EFI_BUFFER_TOO_SMALL   The buffer specified by ImageSize is too small to hold the
469                                  image. The current buffer size needed to hold the image is returned
470                                  in ImageSize.
471   @retval EFI_INVALID_PARAMETER  The Image was NULL.
472   @retval EFI_NOT_FOUND          The current image is not copied to the buffer.
473   @retval EFI_UNSUPPORTED        The operation is not supported.
474   @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
475 
476 **/
477 EFI_STATUS
478 EFIAPI
GetTheImage(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This,IN UINT8 ImageIndex,IN OUT VOID * Image,IN OUT UINTN * ImageSize)479 GetTheImage (
480   IN     EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
481   IN     UINT8                             ImageIndex,
482   IN OUT VOID                              *Image,
483   IN OUT UINTN                             *ImageSize
484   )
485 {
486   EFI_STATUS  Status;
487   UINTN       Size;
488 
489   Status = EFI_SUCCESS;
490 
491   //
492   // Check to make sure index is 1 (only 1 image for this device)
493   //
494   if (ImageIndex != 1) {
495     DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Index Invalid.\n"));
496     Status = EFI_INVALID_PARAMETER;
497     goto cleanup;
498   }
499 
500   if (ImageSize == NULL) {
501     DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - ImageSize Pointer Parameter is NULL.\n"));
502     Status = EFI_INVALID_PARAMETER;
503     goto cleanup;
504   }
505 
506   //
507   // Check the buffer size
508   //
509   Status = FmpDeviceGetSize (&Size);
510   if (EFI_ERROR (Status)) {
511     Size = 0;
512   }
513   if (*ImageSize < Size) {
514     *ImageSize = Size;
515     DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImage() - ImageSize is to small.\n"));
516     Status = EFI_BUFFER_TOO_SMALL;
517     goto cleanup;
518   }
519 
520   if (Image == NULL) {
521     DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Pointer Parameter is NULL.\n"));
522     Status = EFI_INVALID_PARAMETER;
523     goto cleanup;
524   }
525 
526   Status = FmpDeviceGetImage (Image, ImageSize);
527 cleanup:
528 
529   return Status;
530 }
531 
532 /**
533   Helper function to safely retrieve the FMP header from
534   within an EFI_FIRMWARE_IMAGE_AUTHENTICATION structure.
535 
536   @param[in]   Image        Pointer to the image.
537   @param[in]   ImageSize    Size of the image.
538   @param[out]  PayloadSize
539 
540   @retval  !NULL  Valid pointer to the header.
541   @retval  NULL   Structure is bad and pointer cannot be found.
542 
543 **/
544 VOID *
GetFmpHeader(IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION * Image,IN CONST UINTN ImageSize,OUT UINTN * PayloadSize)545 GetFmpHeader (
546   IN  CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,
547   IN  CONST UINTN                              ImageSize,
548   OUT UINTN                                    *PayloadSize
549   )
550 {
551   //
552   // Check to make sure that operation can be safely performed.
553   //
554   if (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) < (UINTN)Image || \
555       ((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize) {
556     //
557     // Pointer overflow. Invalid image.
558     //
559     return NULL;
560   }
561 
562   *PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
563   return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
564 }
565 
566 /**
567   Helper function to safely calculate the size of all headers
568   within an EFI_FIRMWARE_IMAGE_AUTHENTICATION structure.
569 
570   @param[in]  Image                 Pointer to the image.
571   @param[in]  AdditionalHeaderSize  Size of any headers that cannot be calculated by this function.
572 
573   @retval  UINT32>0  Valid size of all the headers.
574   @retval  0         Structure is bad and size cannot be found.
575 
576 **/
577 UINT32
GetAllHeaderSize(IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION * Image,IN UINT32 AdditionalHeaderSize)578 GetAllHeaderSize (
579   IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,
580   IN UINT32                                   AdditionalHeaderSize
581   )
582 {
583   UINT32  CalculatedSize;
584 
585   CalculatedSize = sizeof (Image->MonotonicCount) +
586                    AdditionalHeaderSize +
587                    Image->AuthInfo.Hdr.dwLength;
588 
589   //
590   // Check to make sure that operation can be safely performed.
591   //
592   if (CalculatedSize < sizeof (Image->MonotonicCount) ||
593       CalculatedSize < AdditionalHeaderSize           ||
594       CalculatedSize < Image->AuthInfo.Hdr.dwLength      ) {
595     //
596     // Integer overflow. Invalid image.
597     //
598     return 0;
599   }
600 
601   return CalculatedSize;
602 }
603 
604 /**
605   Checks if the firmware image is valid for the device.
606 
607   This function allows firmware update application to validate the firmware image without
608   invoking the SetImage() first.
609 
610   @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
611   @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.
612                                  The number is between 1 and DescriptorCount.
613   @param[in]  Image              Points to the new image.
614   @param[in]  ImageSize          Size of the new image in bytes.
615   @param[out] ImageUpdatable     Indicates if the new image is valid for update. It also provides,
616                                  if available, additional information if the image is invalid.
617 
618   @retval EFI_SUCCESS            The image was successfully checked.
619   @retval EFI_ABORTED            The operation is aborted.
620   @retval EFI_INVALID_PARAMETER  The Image was NULL.
621   @retval EFI_UNSUPPORTED        The operation is not supported.
622   @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
623 
624 **/
625 EFI_STATUS
626 EFIAPI
CheckTheImage(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This,IN UINT8 ImageIndex,IN CONST VOID * Image,IN UINTN ImageSize,OUT UINT32 * ImageUpdatable)627 CheckTheImage (
628   IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
629   IN  UINT8                             ImageIndex,
630   IN  CONST VOID                        *Image,
631   IN  UINTN                             ImageSize,
632   OUT UINT32                            *ImageUpdatable
633   )
634 {
635   EFI_STATUS  Status;
636   UINTN       RawSize;
637   VOID        *FmpPayloadHeader;
638   UINTN       FmpPayloadSize;
639   UINT32      Version;
640   UINT32      FmpHeaderSize;
641   UINTN       AllHeaderSize;
642   UINT32      Index;
643   VOID        *PublicKeyData;
644   UINTN       PublicKeyDataLength;
645   UINT8       *PublicKeyDataXdr;
646   UINT8       *PublicKeyDataXdrEnd;
647 
648   Status           = EFI_SUCCESS;
649   RawSize          = 0;
650   FmpPayloadHeader = NULL;
651   FmpPayloadSize   = 0;
652   Version          = 0;
653   FmpHeaderSize    = 0;
654   AllHeaderSize    = 0;
655 
656   //
657   // make sure the descriptor has already been loaded
658   //
659   if (!mDescriptorPopulated) {
660     PopulateDescriptor();
661   }
662 
663   if (ImageUpdatable == NULL) {
664     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n"));
665     Status = EFI_INVALID_PARAMETER;
666     goto cleanup;
667   }
668 
669   //
670   //Set to valid and then if any tests fail it will update this flag.
671   //
672   *ImageUpdatable = IMAGE_UPDATABLE_VALID;
673 
674   if (Image == NULL) {
675     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - Image Pointer Parameter is NULL.\n"));
676     //
677     // not sure if this is needed
678     //
679     *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
680     return EFI_INVALID_PARAMETER;
681   }
682 
683   PublicKeyDataXdr    = PcdGetPtr (PcdFmpDevicePkcs7CertBufferXdr);
684   PublicKeyDataXdrEnd = PublicKeyDataXdr + PcdGetSize (PcdFmpDevicePkcs7CertBufferXdr);
685 
686   if (PublicKeyDataXdr == NULL || (PublicKeyDataXdr == PublicKeyDataXdrEnd)) {
687     DEBUG ((DEBUG_ERROR, "FmpDxe: Invalid certificate, skipping it.\n"));
688     Status = EFI_ABORTED;
689   } else {
690     //
691     // Try each key from PcdFmpDevicePkcs7CertBufferXdr
692     //
693     for (Index = 1; PublicKeyDataXdr < PublicKeyDataXdrEnd; Index++) {
694       Index++;
695       DEBUG (
696         (DEBUG_INFO,
697         "FmpDxe: Certificate #%d [%p..%p].\n",
698         Index,
699         PublicKeyDataXdr,
700         PublicKeyDataXdrEnd
701         )
702         );
703 
704       if ((PublicKeyDataXdr + sizeof (UINT32)) > PublicKeyDataXdrEnd) {
705         //
706         // Key data extends beyond end of PCD
707         //
708         DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate size extends beyond end of PCD, skipping it.\n"));
709         Status = EFI_ABORTED;
710         break;
711       }
712       //
713       // Read key length stored in big-endian format
714       //
715       PublicKeyDataLength = SwapBytes32 (*(UINT32 *)(PublicKeyDataXdr));
716       //
717       // Point to the start of the key data
718       //
719       PublicKeyDataXdr += sizeof (UINT32);
720       if (PublicKeyDataXdr + PublicKeyDataLength > PublicKeyDataXdrEnd) {
721         //
722         // Key data extends beyond end of PCD
723         //
724         DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate extends beyond end of PCD, skipping it.\n"));
725         Status = EFI_ABORTED;
726         break;
727       }
728       PublicKeyData = PublicKeyDataXdr;
729       Status = AuthenticateFmpImage (
730                  (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image,
731                  ImageSize,
732                  PublicKeyData,
733                  PublicKeyDataLength
734                  );
735       if (!EFI_ERROR (Status)) {
736         break;
737       }
738       PublicKeyDataXdr += PublicKeyDataLength;
739       PublicKeyDataXdr = (UINT8 *)ALIGN_POINTER (PublicKeyDataXdr, sizeof (UINT32));
740     }
741   }
742 
743   if (EFI_ERROR (Status)) {
744     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - Authentication Failed %r.\n", Status));
745     goto cleanup;
746   }
747 
748   //
749   // Check to make sure index is 1
750   //
751   if (ImageIndex != 1) {
752     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - Image Index Invalid.\n"));
753     *ImageUpdatable = IMAGE_UPDATABLE_INVALID_TYPE;
754     Status = EFI_SUCCESS;
755     goto cleanup;
756   }
757 
758 
759   //
760   // Check the FmpPayloadHeader
761   //
762   FmpPayloadHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );
763   if (FmpPayloadHeader == NULL) {
764     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpHeader failed.\n"));
765     Status = EFI_ABORTED;
766     goto cleanup;
767   }
768   Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);
769   if (EFI_ERROR (Status)) {
770     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", Status));
771     *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
772     Status = EFI_SUCCESS;
773     goto cleanup;
774   }
775 
776   //
777   // Check the lowest supported version
778   //
779   if (Version < mDesc.LowestSupportedImageVersion) {
780     DEBUG (
781       (DEBUG_ERROR,
782       "FmpDxe: CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n",
783       Version, mDesc.LowestSupportedImageVersion)
784       );
785     *ImageUpdatable = IMAGE_UPDATABLE_INVALID_OLD;
786     Status = EFI_SUCCESS;
787     goto cleanup;
788   }
789 
790   //
791   // Get the FmpHeaderSize so we can determine the real payload size
792   //
793   Status = GetFmpPayloadHeaderSize (FmpPayloadHeader, FmpPayloadSize, &FmpHeaderSize);
794   if (EFI_ERROR (Status)) {
795     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpPayloadHeaderSize failed %r.\n", Status));
796     *ImageUpdatable = IMAGE_UPDATABLE_INVALID;
797     Status = EFI_SUCCESS;
798     goto cleanup;
799   }
800 
801   //
802   // Call FmpDevice Lib Check Image on the
803   // Raw payload.  So all headers need stripped off
804   //
805   AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );
806   if (AllHeaderSize == 0) {
807     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetAllHeaderSize failed.\n"));
808     Status = EFI_ABORTED;
809     goto cleanup;
810   }
811   RawSize = ImageSize - AllHeaderSize;
812 
813   //
814   // FmpDeviceLib CheckImage function to do any specific checks
815   //
816   Status = FmpDeviceCheckImage ((((UINT8 *)Image) + AllHeaderSize), RawSize, ImageUpdatable);
817   if (EFI_ERROR (Status)) {
818     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - FmpDeviceLib CheckImage failed. Status = %r\n", Status));
819   }
820 
821 cleanup:
822   return Status;
823 }
824 
825 /**
826   Updates the firmware image of the device.
827 
828   This function updates the hardware with the new firmware image.
829   This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
830   If the firmware image is updatable, the function should perform the following minimal validations
831   before proceeding to do the firmware image update.
832   - Validate the image authentication if image has attribute
833     IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
834     EFI_SECURITY_VIOLATION if the validation fails.
835   - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
836     the image is unsupported. The function can optionally provide more detailed information on
837     why the image is not a supported image.
838   - Validate the data from VendorCode if not null. Image validation must be performed before
839     VendorCode data validation. VendorCode data is ignored or considered invalid if image
840     validation failed. The function returns EFI_ABORTED if the data is invalid.
841 
842   VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
843   the caller did not specify the policy or use the default policy. As an example, vendor can implement
844   a policy to allow an option to force a firmware image update when the abort reason is due to the new
845   firmware image version is older than the current firmware image version or bad image checksum.
846   Sensitive operations such as those wiping the entire firmware image and render the device to be
847   non-functional should be encoded in the image itself rather than passed with the VendorCode.
848   AbortReason enables vendor to have the option to provide a more detailed description of the abort
849   reason to the caller.
850 
851   @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
852   @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.
853                                  The number is between 1 and DescriptorCount.
854   @param[in]  Image              Points to the new image.
855   @param[in]  ImageSize          Size of the new image in bytes.
856   @param[in]  VendorCode         This enables vendor to implement vendor-specific firmware image update policy.
857                                  Null indicates the caller did not specify the policy or use the default policy.
858   @param[in]  Progress           A function used by the driver to report the progress of the firmware update.
859   @param[out] AbortReason        A pointer to a pointer to a null-terminated string providing more
860                                  details for the aborted operation. The buffer is allocated by this function
861                                  with AllocatePool(), and it is the caller's responsibility to free it with a
862                                  call to FreePool().
863 
864   @retval EFI_SUCCESS            The device was successfully updated with the new image.
865   @retval EFI_ABORTED            The operation is aborted.
866   @retval EFI_INVALID_PARAMETER  The Image was NULL.
867   @retval EFI_UNSUPPORTED        The operation is not supported.
868   @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
869 
870 **/
871 EFI_STATUS
872 EFIAPI
SetTheImage(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This,IN UINT8 ImageIndex,IN CONST VOID * Image,IN UINTN ImageSize,IN CONST VOID * VendorCode,IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,OUT CHAR16 ** AbortReason)873 SetTheImage (
874   IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL               *This,
875   IN  UINT8                                          ImageIndex,
876   IN  CONST VOID                                     *Image,
877   IN  UINTN                                          ImageSize,
878   IN  CONST VOID                                     *VendorCode,
879   IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,
880   OUT CHAR16                                         **AbortReason
881   )
882 {
883   EFI_STATUS  Status;
884   UINT32      Updateable;
885   BOOLEAN     BooleanValue;
886   UINT32      FmpHeaderSize;
887   VOID        *FmpHeader;
888   UINTN       FmpPayloadSize;
889   UINT32      AllHeaderSize;
890   UINT32      IncommingFwVersion;
891   UINT32      LastAttemptStatus;
892   UINT32      Version;
893   UINT32      LowestSupportedVersion;
894 
895   Status             = EFI_SUCCESS;
896   Updateable         = 0;
897   BooleanValue       = FALSE;
898   FmpHeaderSize      = 0;
899   FmpHeader          = NULL;
900   FmpPayloadSize     = 0;
901   AllHeaderSize      = 0;
902   IncommingFwVersion = 0;
903   LastAttemptStatus  = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
904 
905 
906   SetLastAttemptVersionInVariable (IncommingFwVersion); //set to 0 to clear any previous results.
907 
908   //
909   // if we have locked the device, then skip the set operation.
910   // it should be blocked by hardware too but we can catch here even faster
911   //
912   if (mFmpDeviceLocked) {
913     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Device is already locked.  Can't update.\n"));
914     Status = EFI_UNSUPPORTED;
915     goto cleanup;
916   }
917 
918   //
919   // Call check image to verify the image
920   //
921   Status = CheckTheImage (This, ImageIndex, Image, ImageSize, &Updateable);
922   if (EFI_ERROR (Status)) {
923     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Check The Image failed with %r.\n", Status));
924     if (Status == EFI_SECURITY_VIOLATION) {
925       LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
926     }
927     goto cleanup;
928   }
929 
930   //
931   // No functional error in CheckTheImage.  Attempt to get the Version to
932   // support better error reporting.
933   //
934   FmpHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );
935   if (FmpHeader == NULL) {
936     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetFmpHeader failed.\n"));
937     Status = EFI_ABORTED;
938     goto cleanup;
939   }
940   Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncommingFwVersion);
941   if (!EFI_ERROR (Status)) {
942     //
943     // Set to actual value
944     //
945     SetLastAttemptVersionInVariable (IncommingFwVersion);
946   }
947 
948 
949   if (Updateable != IMAGE_UPDATABLE_VALID) {
950     DEBUG (
951       (DEBUG_ERROR,
952       "FmpDxed: SetTheImage() - Check The Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n",
953       Updateable)
954       );
955     Status = EFI_ABORTED;
956     goto cleanup;
957   }
958 
959   if (Progress == NULL) {
960     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Invalid progress callback\n"));
961     Status = EFI_INVALID_PARAMETER;
962     goto cleanup;
963   }
964 
965   mProgressFunc = Progress;
966   mProgressSupported = TRUE;
967 
968   //
969   // Checking the image is at least 1%
970   //
971   Status = Progress (1);
972   if (EFI_ERROR (Status)) {
973     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Progress Callback failed with Status %r.\n", Status));
974   }
975 
976   //
977   //Check System Power
978   //
979   Status = CheckSystemPower (&BooleanValue);
980   if (EFI_ERROR (Status)) {
981     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemPower - API call failed %r.\n", Status));
982     goto cleanup;
983   }
984   if (!BooleanValue) {
985     Status = EFI_ABORTED;
986     DEBUG (
987       (DEBUG_ERROR,
988       "FmpDxe: SetTheImage() - CheckSystemPower - returned False.  Update not allowed due to System Power.\n")
989       );
990     LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_BATT;
991     goto cleanup;
992   }
993 
994   Progress (2);
995 
996   //
997   //Check System Thermal
998   //
999   Status = CheckSystemThermal (&BooleanValue);
1000   if (EFI_ERROR (Status)) {
1001     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemThermal - API call failed %r.\n", Status));
1002     goto cleanup;
1003   }
1004   if (!BooleanValue) {
1005     Status = EFI_ABORTED;
1006     DEBUG (
1007       (DEBUG_ERROR,
1008       "FmpDxe: SetTheImage() - CheckSystemThermal - returned False.  Update not allowed due to System Thermal.\n")
1009       );
1010     goto cleanup;
1011   }
1012 
1013   Progress (3);
1014 
1015   //
1016   //Check System Environment
1017   //
1018   Status = CheckSystemEnvironment (&BooleanValue);
1019   if (EFI_ERROR (Status)) {
1020     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemEnvironment - API call failed %r.\n", Status));
1021     goto cleanup;
1022   }
1023   if (!BooleanValue) {
1024     Status = EFI_ABORTED;
1025     DEBUG (
1026       (DEBUG_ERROR,
1027       "FmpDxe: SetTheImage() - CheckSystemEnvironment - returned False.  Update not allowed due to System Environment.\n")
1028       );
1029     goto cleanup;
1030   }
1031 
1032   Progress (4);
1033 
1034   //
1035   // Save LastAttemptStatus as error so that if SetImage never returns the error
1036   // state is recorded.
1037   //
1038   SetLastAttemptStatusInVariable (LastAttemptStatus);
1039 
1040   //
1041   // Strip off all the headers so the device can process its firmware
1042   //
1043   Status = GetFmpPayloadHeaderSize (FmpHeader, FmpPayloadSize, &FmpHeaderSize);
1044   if (EFI_ERROR (Status)) {
1045     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetFmpPayloadHeaderSize failed %r.\n", Status));
1046     goto cleanup;
1047   }
1048 
1049   AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );
1050   if (AllHeaderSize == 0) {
1051     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetAllHeaderSize failed.\n"));
1052     Status = EFI_ABORTED;
1053     goto cleanup;
1054   }
1055 
1056   //
1057   // Indicate that control is handed off to FmpDeviceLib
1058   //
1059   Progress (5);
1060 
1061   //
1062   //Copy the requested image to the firmware using the FmpDeviceLib
1063   //
1064   Status = FmpDeviceSetImage (
1065              (((UINT8 *)Image) + AllHeaderSize),
1066              ImageSize - AllHeaderSize,
1067              VendorCode,
1068              FmpDxeProgress,
1069              IncommingFwVersion,
1070              AbortReason
1071              );
1072   if (EFI_ERROR (Status)) {
1073     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() SetImage from FmpDeviceLib failed. Status =  %r.\n", Status));
1074     goto cleanup;
1075   }
1076 
1077 
1078   //
1079   // Finished the update without error
1080   // Indicate that control has been returned from FmpDeviceLib
1081   //
1082   Progress (99);
1083 
1084   //
1085   // Update the version stored in variable
1086   //
1087   if (!mRuntimeVersionSupported) {
1088     Version = DEFAULT_VERSION;
1089     GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &Version);
1090     SetVersionInVariable (Version);
1091   }
1092 
1093   //
1094   // Update lowest supported variable
1095   //
1096   {
1097     LowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;
1098     GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, &LowestSupportedVersion);
1099     SetLowestSupportedVersionInVariable (LowestSupportedVersion);
1100   }
1101 
1102   LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
1103 
1104 cleanup:
1105   mProgressFunc = NULL;
1106   mProgressSupported = FALSE;
1107   SetLastAttemptStatusInVariable (LastAttemptStatus);
1108 
1109   if (Progress != NULL) {
1110     //
1111     // Set progress to 100 after everything is done including recording Status.
1112     //
1113     Progress (100);
1114   }
1115 
1116   //
1117   // Need repopulate after SetImage is called to
1118   // update LastAttemptVersion and LastAttemptStatus.
1119   //
1120   mDescriptorPopulated = FALSE;
1121 
1122   return Status;
1123 }
1124 
1125 /**
1126   Returns information about the firmware package.
1127 
1128   This function returns package information.
1129 
1130   @param[in]  This                     A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
1131   @param[out] PackageVersion           A version number that represents all the firmware images in the device.
1132                                        The format is vendor specific and new version must have a greater value
1133                                        than the old version. If PackageVersion is not supported, the value is
1134                                        0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version
1135                                        comparison is to be performed using PackageVersionName. A value of
1136                                        0xFFFFFFFD indicates that package version update is in progress.
1137   @param[out] PackageVersionName       A pointer to a pointer to a null-terminated string representing
1138                                        the package version name. The buffer is allocated by this function with
1139                                        AllocatePool(), and it is the caller's responsibility to free it with a
1140                                        call to FreePool().
1141   @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of
1142                                        package version name. A value of 0 indicates the device does not support
1143                                        update of package version name. Length is the number of Unicode characters,
1144                                        including the terminating null character.
1145   @param[out] AttributesSupported      Package attributes that are supported by this device. See 'Package Attribute
1146                                        Definitions' for possible returned values of this parameter. A value of 1
1147                                        indicates the attribute is supported and the current setting value is
1148                                        indicated in AttributesSetting. A value of 0 indicates the attribute is not
1149                                        supported and the current setting value in AttributesSetting is meaningless.
1150   @param[out] AttributesSetting        Package attributes. See 'Package Attribute Definitions' for possible returned
1151                                        values of this parameter
1152 
1153   @retval EFI_SUCCESS                  The package information was successfully returned.
1154   @retval EFI_UNSUPPORTED              The operation is not supported.
1155 
1156 **/
1157 EFI_STATUS
1158 EFIAPI
GetPackageInfo(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This,OUT UINT32 * PackageVersion,OUT CHAR16 ** PackageVersionName,OUT UINT32 * PackageVersionNameMaxLen,OUT UINT64 * AttributesSupported,OUT UINT64 * AttributesSetting)1159 GetPackageInfo (
1160   IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
1161   OUT UINT32                            *PackageVersion,
1162   OUT CHAR16                            **PackageVersionName,
1163   OUT UINT32                            *PackageVersionNameMaxLen,
1164   OUT UINT64                            *AttributesSupported,
1165   OUT UINT64                            *AttributesSetting
1166   )
1167 {
1168   return EFI_UNSUPPORTED;
1169 }
1170 
1171 /**
1172   Updates information about the firmware package.
1173 
1174   This function updates package information.
1175   This function returns EFI_UNSUPPORTED if the package information is not updatable.
1176   VendorCode enables vendor to implement vendor-specific package information update policy.
1177   Null if the caller did not specify this policy or use the default policy.
1178 
1179   @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
1180   @param[in]  Image              Points to the authentication image.
1181                                  Null if authentication is not required.
1182   @param[in]  ImageSize          Size of the authentication image in bytes.
1183                                  0 if authentication is not required.
1184   @param[in]  VendorCode         This enables vendor to implement vendor-specific firmware
1185                                  image update policy.
1186                                  Null indicates the caller did not specify this policy or use
1187                                  the default policy.
1188   @param[in]  PackageVersion     The new package version.
1189   @param[in]  PackageVersionName A pointer to the new null-terminated Unicode string representing
1190                                  the package version name.
1191                                  The string length is equal to or less than the value returned in
1192                                  PackageVersionNameMaxLen.
1193 
1194   @retval EFI_SUCCESS            The device was successfully updated with the new package
1195                                  information.
1196   @retval EFI_INVALID_PARAMETER  The PackageVersionName length is longer than the value
1197                                  returned in PackageVersionNameMaxLen.
1198   @retval EFI_UNSUPPORTED        The operation is not supported.
1199   @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
1200 
1201 **/
1202 EFI_STATUS
1203 EFIAPI
SetPackageInfo(IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL * This,IN CONST VOID * Image,IN UINTN ImageSize,IN CONST VOID * VendorCode,IN UINT32 PackageVersion,IN CONST CHAR16 * PackageVersionName)1204 SetPackageInfo (
1205   IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
1206   IN CONST VOID                        *Image,
1207   IN UINTN                             ImageSize,
1208   IN CONST VOID                        *VendorCode,
1209   IN UINT32                            PackageVersion,
1210   IN CONST CHAR16                      *PackageVersionName
1211   )
1212 {
1213   return EFI_UNSUPPORTED;
1214 }
1215 
1216 /**
1217   Event notification function that is invoked when the event GUID specified by
1218   PcdFmpDeviceLockEventGuid is signaled.
1219 
1220   @param[in] Event    Event whose notification function is being invoked.
1221   @param[in] Context  The pointer to the notification function's context,
1222                       which is implementation-dependent.
1223 **/
1224 VOID
1225 EFIAPI
FmpDxeLockEventNotify(IN EFI_EVENT Event,IN VOID * Context)1226 FmpDxeLockEventNotify (
1227   IN EFI_EVENT  Event,
1228   IN VOID       *Context
1229   )
1230 {
1231   EFI_STATUS  Status;
1232 
1233   if (!mFmpDeviceLocked) {
1234     //
1235     // Lock the firmware device
1236     //
1237     Status = FmpDeviceLock();
1238     if (EFI_ERROR (Status)) {
1239       if (Status != EFI_UNSUPPORTED) {
1240         DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLock() returned error.  Status = %r\n", Status));
1241       } else {
1242         DEBUG ((DEBUG_WARN, "FmpDxe: FmpDeviceLock() returned error.  Status = %r\n", Status));
1243       }
1244     }
1245     mFmpDeviceLocked = TRUE;
1246   }
1247 }
1248 
1249 /**
1250   Function to install FMP instance.
1251 
1252   @param[in]  Handle  The device handle to install a FMP instance on.
1253 
1254   @retval  EFI_SUCCESS            FMP Installed
1255   @retval  EFI_INVALID_PARAMETER  Handle was invalid
1256   @retval  other                  Error installing FMP
1257 
1258 **/
1259 EFI_STATUS
1260 EFIAPI
InstallFmpInstance(IN EFI_HANDLE Handle)1261 InstallFmpInstance (
1262   IN EFI_HANDLE  Handle
1263   )
1264 {
1265   EFI_STATUS                                   Status;
1266   EFI_FIRMWARE_MANAGEMENT_PROTOCOL             *Fmp;
1267   EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  *FmpProgress;
1268 
1269   Status      = EFI_SUCCESS;
1270   Fmp         = NULL;
1271   FmpProgress = NULL;
1272 
1273   //
1274   // Only allow a single FMP Protocol instance to be installed
1275   //
1276   if (mFmpInstalled) {
1277     return EFI_ALREADY_STARTED;
1278   }
1279 
1280   //
1281   // Allocate FMP Protocol instance
1282   //
1283   Fmp = AllocateZeroPool (sizeof (EFI_FIRMWARE_MANAGEMENT_PROTOCOL));
1284   if (Fmp == NULL) {
1285     DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Protocol instance.\n"));
1286     Status = EFI_OUT_OF_RESOURCES;
1287     goto cleanup;
1288   }
1289 
1290   //
1291   // Allocate FMP Progress Protocol instance
1292   //
1293   FmpProgress = AllocateZeroPool (sizeof (EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL));
1294   if (FmpProgress == NULL) {
1295     DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Progress Protocol instance.\n"));
1296     Status = EFI_OUT_OF_RESOURCES;
1297     FreePool (Fmp);
1298     goto cleanup;
1299   }
1300 
1301   //
1302   // Set up FMP Protocol function pointers
1303   //
1304   Fmp->GetImageInfo   = GetTheImageInfo;
1305   Fmp->GetImage       = GetTheImage;
1306   Fmp->SetImage       = SetTheImage;
1307   Fmp->CheckImage     = CheckTheImage;
1308   Fmp->GetPackageInfo = GetPackageInfo;
1309   Fmp->SetPackageInfo = SetPackageInfo;
1310 
1311   //
1312   // Fill in FMP Progress Protocol fields for Version 1
1313   //
1314   FmpProgress->Version                        = 1;
1315   FmpProgress->ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor);
1316   FmpProgress->WatchdogSeconds                = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds);
1317 
1318   //
1319   // Install FMP Protocol and FMP Progress Protocol
1320   //
1321   Status = gBS->InstallMultipleProtocolInterfaces (
1322                   &Handle,
1323                   &gEfiFirmwareManagementProtocolGuid,
1324                   Fmp,
1325                   &gEdkiiFirmwareManagementProgressProtocolGuid,
1326                   FmpProgress,
1327                   NULL
1328                   );
1329 
1330   if (EFI_ERROR (Status)) {
1331     DEBUG ((DEBUG_ERROR, "FmpDxe: FMP Protocol install error. Status = %r.\n", Status));
1332     FreePool (Fmp);
1333     goto cleanup;
1334   }
1335 
1336   DEBUG ((DEBUG_INFO, "FmpDxe: FMP Protocol Installed!\n"));
1337   mFmpInstalled = TRUE;
1338 
1339 cleanup:
1340 
1341   return Status;
1342 }
1343 
1344 /**
1345   Main entry for this driver/library.
1346 
1347   @param[in] ImageHandle  Image handle this driver.
1348   @param[in] SystemTable  Pointer to SystemTable.
1349 
1350 **/
1351 EFI_STATUS
1352 EFIAPI
FmpDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1353 FmpDxeEntryPoint (
1354   IN EFI_HANDLE        ImageHandle,
1355   IN EFI_SYSTEM_TABLE  *SystemTable
1356   )
1357 {
1358   EFI_STATUS  Status;
1359   EFI_GUID    *LockGuid;
1360 
1361   //
1362   // Verify that a new FILE_GUID value has been provided in the <Defines>
1363   // section of this module.  The FILE_GUID is the ESRT GUID that must be
1364   // unique for each updatable firmware image.
1365   //
1366   if (CompareGuid (&mDefaultModuleFileGuid, &gEfiCallerIdGuid)) {
1367     DEBUG ((DEBUG_ERROR, "FmpDxe: Use of default FILE_GUID detected.  FILE_GUID must be set to a unique value.\n"));
1368     ASSERT (FALSE);
1369     return EFI_UNSUPPORTED;
1370   }
1371 
1372   //
1373   // Get the ImageIdName value for the EFI_FIRMWARE_IMAGE_DESCRIPTOR from a PCD.
1374   //
1375   mImageIdName = (CHAR16 *) PcdGetPtr (PcdFmpDeviceImageIdName);
1376   if (PcdGetSize (PcdFmpDeviceImageIdName) <= 2 || mImageIdName[0] == 0) {
1377     //
1378     // PcdFmpDeviceImageIdName must be set to a non-empty Unicode string
1379     //
1380     DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib PcdFmpDeviceImageIdName is an empty string.\n"));
1381     ASSERT (FALSE);
1382   }
1383 
1384   //
1385   // Detects if PcdFmpDevicePkcs7CertBufferXdr contains a test key.
1386   //
1387   DetectTestKey ();
1388 
1389   if (IsLockFmpDeviceAtLockEventGuidRequired ()) {
1390     //
1391     // Lock all UEFI Variables used by this module.
1392     //
1393     Status = LockAllFmpVariables ();
1394     if (EFI_ERROR (Status)) {
1395       DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variables.  Status = %r.\n", Status));
1396     } else {
1397       DEBUG ((DEBUG_INFO, "FmpDxe: All variables locked\n"));
1398     }
1399 
1400     //
1401     // Register notify function to lock the FMP device.
1402     // The lock event GUID is retrieved from PcdFmpDeviceLockEventGuid.
1403     // If PcdFmpDeviceLockEventGuid is not the size of an EFI_GUID, then
1404     // gEfiEndOfDxeEventGroupGuid is used.
1405     //
1406     LockGuid = &gEfiEndOfDxeEventGroupGuid;
1407     if (PcdGetSize (PcdFmpDeviceLockEventGuid) == sizeof (EFI_GUID)) {
1408       LockGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceLockEventGuid);
1409     }
1410     DEBUG ((DEBUG_INFO, "FmpDxe: Lock GUID: %g\n", LockGuid));
1411 
1412     Status = gBS->CreateEventEx (
1413                     EVT_NOTIFY_SIGNAL,
1414                     TPL_CALLBACK,
1415                     FmpDxeLockEventNotify,
1416                     NULL,
1417                     LockGuid,
1418                     &mFmpDeviceLockEvent
1419                     );
1420     if (EFI_ERROR (Status)) {
1421       DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to register notification.  Status = %r\n", Status));
1422     }
1423     ASSERT_EFI_ERROR (Status);
1424   } else {
1425     DEBUG ((DEBUG_VERBOSE, "FmpDxe: Not registering notification to call FmpDeviceLock() because mfg mode\n"));
1426   }
1427 
1428   //
1429   // Register with library the install function so if the library uses
1430   // UEFI driver model/driver binding protocol it can install FMP on its device handle
1431   // If library is simple lib that does not use driver binding then it should return
1432   // unsupported and this will install the FMP instance on the ImageHandle
1433   //
1434   Status = RegisterFmpInstaller (InstallFmpInstance);
1435   if (Status == EFI_UNSUPPORTED) {
1436     DEBUG ((DEBUG_INFO, "FmpDxe: FmpDeviceLib registration returned EFI_UNSUPPORTED.  Installing single FMP instance.\n"));
1437     Status = InstallFmpInstance (ImageHandle);
1438   } else if (EFI_ERROR (Status)) {
1439     DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib registration returned %r.  No FMP installed.\n", Status));
1440   } else {
1441     DEBUG ((
1442       DEBUG_INFO,
1443       "FmpDxe: FmpDeviceLib registration returned EFI_SUCCESS.  Expect FMP to be installed during the BDS/Device connection phase.\n"
1444       ));
1445   }
1446 
1447   return Status;
1448 }
1449