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