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