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