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