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