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