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