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