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