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