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