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