+++ /dev/null
-/** @file\r
- Supports Capsule Dependency Expression.\r
-\r
- Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-#include "FmpDxe.h"\r
-#include "Dependency.h"\r
-\r
-//\r
-// Define the initial size of the dependency expression evaluation stack\r
-//\r
-#define DEPEX_STACK_SIZE_INCREMENT 0x1000\r
-\r
-//\r
-// Type of stack element\r
-//\r
-typedef enum {\r
- BooleanType,\r
- VersionType\r
-} ELEMENT_TYPE;\r
-\r
-//\r
-// Value of stack element\r
-//\r
-typedef union {\r
- BOOLEAN Boolean;\r
- UINT32 Version;\r
-} ELEMENT_VALUE;\r
-\r
-//\r
-// Stack element used to evaluate dependency expressions\r
-//\r
-typedef struct {\r
- ELEMENT_VALUE Value;\r
- ELEMENT_TYPE Type;\r
-} DEPEX_ELEMENT;\r
-\r
-//\r
-// Global variable used to support dependency evaluation\r
-//\r
-UINTN mNumberOfFmpInstance = 0;\r
-EFI_FIRMWARE_IMAGE_DESCRIPTOR **mFmpImageInfoBuf = NULL;\r
-\r
-//\r
-// Indicates the status of dependency check, default value is DEPENDENCIES_SATISFIED.\r
-//\r
-UINT8 mDependenciesCheckStatus = DEPENDENCIES_SATISFIED;\r
-\r
-//\r
-// Global stack used to evaluate dependency expressions\r
-//\r
-DEPEX_ELEMENT *mDepexEvaluationStack = NULL;\r
-DEPEX_ELEMENT *mDepexEvaluationStackEnd = NULL;\r
-DEPEX_ELEMENT *mDepexEvaluationStackPointer = NULL;\r
-\r
-/**\r
- Grow size of the Depex stack\r
-\r
- @retval EFI_SUCCESS Stack successfully growed.\r
- @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.\r
-\r
-**/\r
-EFI_STATUS\r
-GrowDepexStack (\r
- VOID\r
- )\r
-{\r
- DEPEX_ELEMENT *NewStack;\r
- UINTN Size;\r
-\r
- Size = DEPEX_STACK_SIZE_INCREMENT;\r
- if (mDepexEvaluationStack != NULL) {\r
- Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);\r
- }\r
-\r
- NewStack = AllocatePool (Size * sizeof (DEPEX_ELEMENT));\r
- if (NewStack == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- if (mDepexEvaluationStack != NULL) {\r
- //\r
- // Copy to Old Stack to the New Stack\r
- //\r
- CopyMem (\r
- NewStack,\r
- mDepexEvaluationStack,\r
- (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (DEPEX_ELEMENT)\r
- );\r
-\r
- //\r
- // Free The Old Stack\r
- //\r
- FreePool (mDepexEvaluationStack);\r
- }\r
-\r
- //\r
- // Make the Stack pointer point to the old data in the new stack\r
- //\r
- mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);\r
- mDepexEvaluationStack = NewStack;\r
- mDepexEvaluationStackEnd = NewStack + Size;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Push an element onto the Stack.\r
-\r
- @param[in] Value Value to push.\r
- @param[in] Type Element Type\r
-\r
- @retval EFI_SUCCESS The value was pushed onto the stack.\r
- @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.\r
- @retval EFI_INVALID_PARAMETER Wrong stack element type.\r
-\r
-**/\r
-EFI_STATUS\r
-Push (\r
- IN UINT32 Value,\r
- IN UINTN Type\r
- )\r
-{\r
- EFI_STATUS Status;\r
- DEPEX_ELEMENT Element;\r
-\r
- //\r
- // Check Type\r
- //\r
- if (Type != BooleanType && Type != VersionType) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check for a stack overflow condition\r
- //\r
- if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {\r
- //\r
- // Grow the stack\r
- //\r
- Status = GrowDepexStack ();\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
- Element.Value.Version = Value;\r
- Element.Type = Type;\r
-\r
- //\r
- // Push the item onto the stack\r
- //\r
- *mDepexEvaluationStackPointer = Element;\r
- mDepexEvaluationStackPointer++;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Pop an element from the stack.\r
-\r
- @param[out] Element Element to pop.\r
- @param[in] Type Type of element.\r
-\r
- @retval EFI_SUCCESS The value was popped onto the stack.\r
- @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.\r
- @retval EFI_INVALID_PARAMETER Type is mismatched.\r
-\r
-**/\r
-EFI_STATUS\r
-Pop (\r
- OUT DEPEX_ELEMENT *Element,\r
- IN ELEMENT_TYPE Type\r
- )\r
-{\r
- //\r
- // Check for a stack underflow condition\r
- //\r
- if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {\r
- return EFI_ACCESS_DENIED;\r
- }\r
-\r
- //\r
- // Pop the item off the stack\r
- //\r
- mDepexEvaluationStackPointer--;\r
- *Element = *mDepexEvaluationStackPointer;\r
- if ((*Element).Type != Type) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Evaluate the dependencies.\r
-\r
- @param[in] Dependencies Dependency expressions.\r
- @param[in] DependenciesSize Size of Dependency expressions.\r
-\r
- @retval TRUE Dependency expressions evaluate to TRUE.\r
- @retval FALSE Dependency expressions evaluate to FALSE.\r
-\r
-**/\r
-BOOLEAN\r
-EvaluateDependencies (\r
- IN CONST EFI_FIRMWARE_IMAGE_DEP * Dependencies,\r
- IN CONST UINTN DependenciesSize\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 *Iterator;\r
- UINT8 Index;\r
- DEPEX_ELEMENT Element1;\r
- DEPEX_ELEMENT Element2;\r
- GUID ImageTypeId;\r
- UINT32 Version;\r
-\r
- if (Dependencies == NULL || DependenciesSize == 0) {\r
- return FALSE;\r
- }\r
-\r
- //\r
- // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by\r
- // incorrectly formed DEPEX expressions\r
- //\r
- mDepexEvaluationStackPointer = mDepexEvaluationStack;\r
-\r
- Iterator = (UINT8 *) Dependencies->Dependencies;\r
- while (Iterator < (UINT8 *) Dependencies->Dependencies + DependenciesSize) {\r
- switch (*Iterator)\r
- {\r
- case EFI_FMP_DEP_PUSH_GUID:\r
- if (Iterator + sizeof (EFI_GUID) >= (UINT8 *) Dependencies->Dependencies + DependenciesSize) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Error;\r
- }\r
-\r
- CopyGuid (&ImageTypeId, (EFI_GUID *) (Iterator + 1));\r
- Iterator = Iterator + sizeof (EFI_GUID);\r
-\r
- for (Index = 0; Index < mNumberOfFmpInstance; Index ++){\r
- if (mFmpImageInfoBuf[Index] == NULL) {\r
- continue;\r
- }\r
- if(CompareGuid (&mFmpImageInfoBuf[Index]->ImageTypeId, &ImageTypeId)){\r
- Status = Push (mFmpImageInfoBuf[Index]->Version, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- }\r
- }\r
- if (Index == mNumberOfFmpInstance) {\r
- Status = EFI_NOT_FOUND;\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_PUSH_VERSION:\r
- if (Iterator + sizeof (UINT32) >= (UINT8 *) Dependencies->Dependencies + DependenciesSize ) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Error;\r
- }\r
-\r
- Version = *(UINT32 *) (Iterator + 1);\r
- Status = Push (Version, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Iterator = Iterator + sizeof (UINT32);\r
- break;\r
- case EFI_FMP_DEP_VERSION_STR:\r
- Iterator += AsciiStrnLenS ((CHAR8 *) Iterator, DependenciesSize - (Iterator - Dependencies->Dependencies));\r
- break;\r
- case EFI_FMP_DEP_AND:\r
- Status = Pop (&Element1, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Pop (&Element2, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Push (Element1.Value.Boolean & Element2.Value.Boolean, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_OR:\r
- Status = Pop (&Element1, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Pop(&Element2, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Push (Element1.Value.Boolean | Element2.Value.Boolean, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_NOT:\r
- Status = Pop (&Element1, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Push (!(Element1.Value.Boolean), BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_TRUE:\r
- Status = Push (TRUE, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_FALSE:\r
- Status = Push (FALSE, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_EQ:\r
- Status = Pop (&Element1, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Pop (&Element2, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = (Element1.Value.Version == Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_GT:\r
- Status = Pop (&Element1, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Pop (&Element2, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = (Element1.Value.Version > Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_GTE:\r
- Status = Pop (&Element1, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Pop (&Element2, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = (Element1.Value.Version >= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_LT:\r
- Status = Pop (&Element1, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Pop (&Element2, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = (Element1.Value.Version < Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_LTE:\r
- Status = Pop (&Element1, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = Pop (&Element2, VersionType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- Status = (Element1.Value.Version <= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- break;\r
- case EFI_FMP_DEP_END:\r
- Status = Pop (&Element1, BooleanType);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- return Element1.Value.Boolean;\r
- default:\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Error;\r
- }\r
- Iterator++;\r
- }\r
-\r
-Error:\r
-\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): EvaluateDependencies() - RESULT = FALSE (Status = %r)\n", mImageIdName, Status));\r
- return FALSE;\r
-}\r
-\r
-/**\r
- Validate the dependency expression and output its size.\r
-\r
- @param[in] ImageDepex Pointer to the EFI_FIRMWARE_IMAGE_DEP.\r
- @param[in] MaxDepexSize Max size of the dependency.\r
- @param[out] DepexSize Size of dependency.\r
-\r
- @retval TRUE The capsule is valid.\r
- @retval FALSE The capsule is invalid.\r
-\r
-**/\r
-BOOLEAN\r
-ValidateImageDepex (\r
- IN EFI_FIRMWARE_IMAGE_DEP *ImageDepex,\r
- IN CONST UINTN MaxDepexSize,\r
- OUT UINT32 *DepexSize\r
- )\r
-{\r
- UINT8 *Depex;\r
-\r
- *DepexSize = 0;\r
- Depex = ImageDepex->Dependencies;\r
- while (Depex < ImageDepex->Dependencies + MaxDepexSize) {\r
- switch (*Depex)\r
- {\r
- case EFI_FMP_DEP_PUSH_GUID:\r
- Depex += sizeof (EFI_GUID) + 1;\r
- break;\r
- case EFI_FMP_DEP_PUSH_VERSION:\r
- Depex += sizeof (UINT32) + 1;\r
- break;\r
- case EFI_FMP_DEP_VERSION_STR:\r
- Depex += AsciiStrnLenS ((CHAR8 *) Depex, ImageDepex->Dependencies + MaxDepexSize - Depex) + 1;\r
- break;\r
- case EFI_FMP_DEP_AND:\r
- case EFI_FMP_DEP_OR:\r
- case EFI_FMP_DEP_NOT:\r
- case EFI_FMP_DEP_TRUE:\r
- case EFI_FMP_DEP_FALSE:\r
- case EFI_FMP_DEP_EQ:\r
- case EFI_FMP_DEP_GT:\r
- case EFI_FMP_DEP_GTE:\r
- case EFI_FMP_DEP_LT:\r
- case EFI_FMP_DEP_LTE:\r
- Depex += 1;\r
- break;\r
- case EFI_FMP_DEP_END:\r
- Depex += 1;\r
- *DepexSize = (UINT32)(Depex - ImageDepex->Dependencies);\r
- return TRUE;\r
- default:\r
- return FALSE;\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-\r
-/**\r
- Get the size of dependencies. Assume the dependencies is validated before\r
- calling this function.\r
-\r
- @param[in] Dependencies Pointer to the EFI_FIRMWARE_IMAGE_DEP.\r
-\r
- @retval The size of dependencies.\r
-\r
-**/\r
-UINTN\r
-GetDepexSize (\r
- IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies\r
- )\r
-{\r
- UINTN Index;\r
-\r
- if (Dependencies == NULL) {\r
- return 0;\r
- }\r
-\r
- Index = 0;\r
- while (Dependencies->Dependencies[Index] != EFI_FMP_DEP_END) {\r
- Index ++;\r
- }\r
-\r
- return Index + 1;\r
-}\r
-\r
-/**\r
- Check dependency for firmware update.\r
-\r
- @param[in] ImageTypeId Image Type Id.\r
- @param[in] Version New version.\r
- @param[in] Dependencies The dependencies.\r
- @param[in] DependenciesSize Size of the dependencies\r
- @param[out] IsSatisfied Indicate the dependencies is satisfied or not.\r
-\r
- @retval EFI_SUCCESS Dependency Evaluation is successful.\r
- @retval Others Dependency Evaluation fails with unexpected error.\r
-\r
-**/\r
-EFI_STATUS\r
-EvaluateImageDependencies (\r
- IN CONST EFI_GUID ImageTypeId,\r
- IN CONST UINT32 Version,\r
- IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies,\r
- IN CONST UINT32 DependenciesSize,\r
- OUT BOOLEAN *IsSatisfied\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN Index;\r
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
- UINTN ImageInfoSize;\r
- UINT32 FmpImageInfoDescriptorVer;\r
- UINT8 FmpImageInfoCount;\r
- UINTN DescriptorSize;\r
- UINT32 PackageVersion;\r
- CHAR16 *PackageVersionName;\r
- UINTN DepexSize;\r
-\r
- *IsSatisfied = TRUE;\r
- PackageVersionName = NULL;\r
-\r
- //\r
- // Get ImageDescriptors of all FMP instances, and archive them for depex evaluation.\r
- //\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiFirmwareManagementProtocolGuid,\r
- NULL,\r
- &mNumberOfFmpInstance,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_ABORTED;\r
- }\r
-\r
- mFmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * mNumberOfFmpInstance);\r
- if (mFmpImageInfoBuf == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiFirmwareManagementProtocolGuid,\r
- (VOID **) &Fmp\r
- );\r
- if (EFI_ERROR(Status)) {\r
- continue;\r
- }\r
-\r
- ImageInfoSize = 0;\r
- Status = Fmp->GetImageInfo (\r
- Fmp,\r
- &ImageInfoSize,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL\r
- );\r
- if (Status != EFI_BUFFER_TOO_SMALL) {\r
- continue;\r
- }\r
-\r
- mFmpImageInfoBuf[Index] = AllocateZeroPool (ImageInfoSize);\r
- if (mFmpImageInfoBuf[Index] == NULL) {\r
- continue;\r
- }\r
-\r
- Status = Fmp->GetImageInfo (\r
- Fmp,\r
- &ImageInfoSize, // ImageInfoSize\r
- mFmpImageInfoBuf[Index], // ImageInfo\r
- &FmpImageInfoDescriptorVer, // DescriptorVersion\r
- &FmpImageInfoCount, // DescriptorCount\r
- &DescriptorSize, // DescriptorSize\r
- &PackageVersion, // PackageVersion\r
- &PackageVersionName // PackageVersionName\r
- );\r
- if (EFI_ERROR(Status)) {\r
- FreePool (mFmpImageInfoBuf[Index]);\r
- mFmpImageInfoBuf[Index] = NULL;\r
- continue;\r
- }\r
-\r
- if (PackageVersionName != NULL) {\r
- FreePool (PackageVersionName);\r
- PackageVersionName = NULL;\r
- }\r
- }\r
-\r
- //\r
- // Step 1 - Evaluate firmware image's depex, against the version of other Fmp instances.\r
- //\r
- if (Dependencies != NULL) {\r
- *IsSatisfied = EvaluateDependencies (Dependencies, DependenciesSize);\r
- }\r
-\r
- if (!*IsSatisfied) {\r
- goto cleanup;\r
- }\r
-\r
- //\r
- // Step 2 - Evaluate the depex of all other Fmp instances, against the new version in\r
- // the firmware image.\r
- //\r
-\r
- //\r
- // Update the new version to mFmpImageInfoBuf.\r
- //\r
- for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
- if (mFmpImageInfoBuf[Index] != NULL) {\r
- if (CompareGuid (&ImageTypeId, &mFmpImageInfoBuf[Index]->ImageTypeId)) {\r
- mFmpImageInfoBuf[Index]->Version = Version;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Evaluate the Dependencies one by one.\r
- //\r
- for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
- if (mFmpImageInfoBuf[Index] != NULL) {\r
- //\r
- // Skip the Fmp instance to be "SetImage".\r
- //\r
- if (CompareGuid (&ImageTypeId, &mFmpImageInfoBuf[Index]->ImageTypeId)) {\r
- continue;\r
- }\r
- if ((mFmpImageInfoBuf[Index]->AttributesSupported & IMAGE_ATTRIBUTE_DEPENDENCY) &&\r
- mFmpImageInfoBuf[Index]->Dependencies != NULL) {\r
- //\r
- // Get the size of depex.\r
- // Assume that the dependencies in EFI_FIRMWARE_IMAGE_DESCRIPTOR is validated when PopulateDescriptor().\r
- //\r
- DepexSize = GetDepexSize (mFmpImageInfoBuf[Index]->Dependencies);\r
- if (DepexSize > 0) {\r
- *IsSatisfied = EvaluateDependencies (mFmpImageInfoBuf[Index]->Dependencies, DepexSize);\r
- if (!*IsSatisfied) {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
-cleanup:\r
- if (mFmpImageInfoBuf != NULL) {\r
- for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {\r
- if (mFmpImageInfoBuf[Index] != NULL) {\r
- FreePool (mFmpImageInfoBuf[Index]);\r
- }\r
- }\r
- FreePool (mFmpImageInfoBuf);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
+++ /dev/null
-/** @file\r
- Fmp Capsule Dependency support functions for Firmware Management Protocol based\r
- firmware updates.\r
-\r
- Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#ifndef __DEPENDENCY_H__\r
-#define __DEPENDENCY_H__\r
-\r
-#include <Library/UefiLib.h>\r
-#include <Protocol/FirmwareManagement.h>\r
-\r
-#define DEPENDENCIES_SATISFIED 0\r
-#define DEPENDENCIES_UNSATISFIED 1\r
-#define DEPENDENCIES_INVALID 2\r
-\r
-extern UINT8 mDependenciesCheckStatus;\r
-\r
-/**\r
- Validate the dependency expression and output its size.\r
-\r
- @param[in] ImageDepex Pointer to the EFI_FIRMWARE_IMAGE_DEP.\r
- @param[in] MaxDepexSize Max size of the dependency.\r
- @param[out] DepexSize Size of dependency.\r
-\r
- @retval TRUE The capsule is valid.\r
- @retval FALSE The capsule is invalid.\r
-\r
-**/\r
-BOOLEAN\r
-ValidateImageDepex (\r
- IN EFI_FIRMWARE_IMAGE_DEP *ImageDepex,\r
- IN CONST UINTN MaxDepexSize,\r
- OUT UINT32 *DepexSize\r
- );\r
-\r
-/**\r
- Check dependency for firmware update.\r
-\r
- @param[in] ImageTypeId Image Type Id.\r
- @param[in] Version New version.\r
- @param[in] Dependencies The dependencies.\r
- @param[in] DepexSize Size of the dependencies\r
- @param[out] IsSatisfied Indicate the dependencies is satisfied or not.\r
-\r
- @retval EFI_SUCCESS Dependency Evaluation is successful.\r
- @retval Others Dependency Evaluation fails with unexpected error.\r
-\r
-**/\r
-EFI_STATUS\r
-EvaluateImageDependencies (\r
- IN CONST EFI_GUID ImageTypeId,\r
- IN CONST UINT32 Version,\r
- IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies,\r
- IN CONST UINT32 DepexSize,\r
- OUT BOOLEAN *IsSatisfied\r
- );\r
-\r
-#endif\r
\r
#include "FmpDxe.h"\r
#include "VariableSupport.h"\r
-#include "Dependency.h"\r
\r
///\r
/// FILE_GUID from FmpDxe.inf. When FmpDxe.inf is used in a platform, the\r
NULL, // LsvVariableName\r
NULL, // LastAttemptStatusVariableName\r
NULL, // LastAttemptVersionVariableName\r
- NULL // FmpStateVariableName\r
+ NULL, // FmpStateVariableName\r
+ TRUE // DependenciesSatisfied\r
};\r
\r
///\r
)\r
{\r
EFI_STATUS Status;\r
- VOID *Image;\r
- UINTN ImageSize;\r
- BOOLEAN IsDepexValid;\r
- UINT32 DepexSize;\r
-\r
- Image = NULL;\r
- ImageSize = 0;\r
+ UINT32 DependenciesSize;\r
\r
if (Private->DescriptorPopulated) {\r
return;\r
Private->Descriptor.LastAttemptStatus = GetLastAttemptStatusFromVariable (Private);\r
\r
//\r
- // Get the dependency from the FmpDeviceLib and populate it to the descriptor.\r
+ // Get the dependency from the FmpDependencyDeviceLib.\r
//\r
Private->Descriptor.Dependencies = NULL;\r
\r
//\r
// Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY\r
//\r
- if (Private->Descriptor.AttributesSupported & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
- //\r
- // The parameter "Image" of FmpDeviceGetImage() is extended to contain the dependency.\r
- // Get the dependency from the Image.\r
- //\r
- ImageSize = Private->Descriptor.Size;\r
- Image = AllocatePool (ImageSize);\r
- if (Image != NULL) {\r
- Status = FmpDeviceGetImage (Image, &ImageSize);\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- FreePool (Image);\r
- Image = AllocatePool (ImageSize);\r
- if (Image != NULL) {\r
- Status = FmpDeviceGetImage (Image, &ImageSize);\r
- }\r
- }\r
- }\r
- if (!EFI_ERROR (Status) && Image != NULL) {\r
- IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP *) Image, ImageSize, &DepexSize);\r
- if (IsDepexValid) {\r
- Private->Descriptor.Dependencies = AllocatePool (DepexSize);\r
- if (Private->Descriptor.Dependencies != NULL) {\r
- CopyMem (Private->Descriptor.Dependencies->Dependencies, Image, DepexSize);\r
- }\r
- }\r
- }\r
+ if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
+ Private->Descriptor.Dependencies = GetFmpDependency (&DependenciesSize);\r
}\r
\r
Private->DescriptorPopulated = TRUE;\r
-\r
- if (Image != NULL) {\r
- FreePool (Image);\r
- }\r
}\r
\r
/**\r
EFI_STATUS Status;\r
FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private;\r
UINTN Size;\r
- UINT8 *ImageBuffer;\r
- UINTN ImageBufferSize;\r
- UINT32 DepexSize;\r
\r
if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
return EFI_UNSUPPORTED;\r
}\r
\r
- Status = EFI_SUCCESS;\r
- ImageBuffer = NULL;\r
- DepexSize = 0;\r
+ Status = EFI_SUCCESS;\r
\r
//\r
// Retrieve the private context structure\r
if (EFI_ERROR (Status)) {\r
Size = 0;\r
}\r
-\r
- //\r
- // The parameter "Image" of FmpDeviceGetImage() is extended to contain the dependency.\r
- // Get the Fmp Payload from the Image.\r
- //\r
- ImageBufferSize = Size;\r
- ImageBuffer = AllocatePool (ImageBufferSize);\r
- if (ImageBuffer == NULL) {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - AllocatePool fails.\n", mImageIdName));\r
- Status = EFI_NOT_FOUND;\r
- goto cleanup;\r
- }\r
- Status = FmpDeviceGetImage (ImageBuffer, &ImageBufferSize);\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- FreePool (ImageBuffer);\r
- ImageBuffer = AllocatePool (ImageBufferSize);\r
- if (ImageBuffer == NULL) {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - AllocatePool fails.\n", mImageIdName));\r
- Status = EFI_NOT_FOUND;\r
- goto cleanup;\r
- }\r
- Status = FmpDeviceGetImage (ImageBuffer, &ImageBufferSize);\r
- }\r
- if (EFI_ERROR (Status)) {\r
- goto cleanup;\r
- }\r
-\r
- //\r
- // Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY\r
- //\r
- if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
- //\r
- // Validate the dependency to get its size.\r
- //\r
- ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP *) ImageBuffer, ImageBufferSize, &DepexSize);\r
- }\r
-\r
- if (*ImageSize < ImageBufferSize - DepexSize) {\r
- *ImageSize = ImageBufferSize - DepexSize;\r
+ if (*ImageSize < Size) {\r
+ *ImageSize = Size;\r
DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImage() - ImageSize is to small.\n", mImageIdName));\r
Status = EFI_BUFFER_TOO_SMALL;\r
goto cleanup;\r
goto cleanup;\r
}\r
\r
- //\r
- // Image is after the dependency expression.\r
- //\r
- *ImageSize = ImageBufferSize - DepexSize;\r
- CopyMem (Image, ImageBuffer + DepexSize, *ImageSize);\r
- Status = EFI_SUCCESS;\r
-\r
+ Status = FmpDeviceGetImage (Image, ImageSize);\r
cleanup:\r
- if (ImageBuffer != NULL) {\r
- FreePool (ImageBuffer);\r
- }\r
\r
return Status;\r
}\r
Helper function to safely retrieve the FMP header from\r
within an EFI_FIRMWARE_IMAGE_AUTHENTICATION structure.\r
\r
- @param[in] Image Pointer to the image.\r
- @param[in] ImageSize Size of the image.\r
+ @param[in] Image Pointer to the image.\r
+ @param[in] ImageSize Size of the image.\r
+ @param[in] AdditionalHeaderSize Size of any headers that cannot be calculated by this function.\r
@param[out] PayloadSize\r
\r
@retval !NULL Valid pointer to the header.\r
GetFmpHeader (\r
IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,\r
IN CONST UINTN ImageSize,\r
+ IN CONST UINTN AdditionalHeaderSize,\r
OUT UINTN *PayloadSize\r
)\r
{\r
//\r
// Check to make sure that operation can be safely performed.\r
//\r
- if (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) < (UINTN)Image || \\r
- ((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize) {\r
+ if (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) + AdditionalHeaderSize < (UINTN)Image || \\r
+ ((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) + AdditionalHeaderSize >= (UINTN)Image + ImageSize) {\r
//\r
// Pointer overflow. Invalid image.\r
//\r
return NULL;\r
}\r
\r
- *PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);\r
- return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);\r
+ *PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength + AdditionalHeaderSize);\r
+ return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength + AdditionalHeaderSize);\r
}\r
\r
/**\r
UINT8 *PublicKeyDataXdrEnd;\r
EFI_FIRMWARE_IMAGE_DEP *Dependencies;\r
UINT32 DependenciesSize;\r
- BOOLEAN IsDepexValid;\r
- BOOLEAN IsDepexSatisfied;\r
\r
Status = EFI_SUCCESS;\r
RawSize = 0;\r
//\r
*ImageUpdatable = IMAGE_UPDATABLE_VALID;\r
\r
+ //\r
+ // Set to satisfied and then if dependency evaluates to false it will update this flag.\r
+ //\r
+ Private->DependenciesSatisfied = TRUE;\r
+\r
if (Image == NULL) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Pointer Parameter is NULL.\n", mImageIdName));\r
//\r
goto cleanup;\r
}\r
\r
+ //\r
+ // Get the dependency from Image.\r
+ //\r
+ Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize);\r
\r
//\r
// Check the FmpPayloadHeader\r
//\r
- FmpPayloadHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );\r
+ FmpPayloadHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, DependenciesSize, &FmpPayloadSize );\r
if (FmpPayloadHeader == NULL) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpHeader failed.\n", mImageIdName));\r
Status = EFI_ABORTED;\r
}\r
Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);\r
if (EFI_ERROR (Status)) {\r
- //\r
- // Check if there is dependency expression\r
- //\r
- IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP*) FmpPayloadHeader, FmpPayloadSize, &DependenciesSize);\r
- if (IsDepexValid && (DependenciesSize < FmpPayloadSize)) {\r
- //\r
- // Fmp payload is after dependency expression\r
- //\r
- Dependencies = (EFI_FIRMWARE_IMAGE_DEP*) FmpPayloadHeader;\r
- FmpPayloadHeader = (UINT8 *) Dependencies + DependenciesSize;\r
- FmpPayloadSize = FmpPayloadSize - DependenciesSize;\r
- Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));\r
- *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
- Status = EFI_SUCCESS;\r
- goto cleanup;\r
- }\r
- } else {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency is invalid.\n", mImageIdName));\r
- mDependenciesCheckStatus = DEPENDENCIES_INVALID;\r
- *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
- Status = EFI_SUCCESS;\r
- goto cleanup;\r
- }\r
- } else {\r
- DEBUG ((DEBUG_WARN, "FmpDxe(%s): CheckTheImage() - No dependency associated in image.\n", mImageIdName));\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));\r
+ *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+ Status = EFI_SUCCESS;\r
+ goto cleanup;\r
}\r
\r
//\r
//\r
// Evaluate dependency expression\r
//\r
- Status = EvaluateImageDependencies (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize, &IsDepexSatisfied);\r
- if (!IsDepexSatisfied || EFI_ERROR (Status)) {\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed %r.\n", mImageIdName, Status));\r
- } else {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency is not satisfied.\n", mImageIdName));\r
- }\r
- mDependenciesCheckStatus = DEPENDENCIES_UNSATISFIED;\r
+ Private->DependenciesSatisfied = CheckFmpDependency (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize);\r
+ if (!Private->DependenciesSatisfied) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed.\n", mImageIdName));\r
*ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
Status = EFI_SUCCESS;\r
goto cleanup;\r
UINT32 LowestSupportedVersion;\r
EFI_FIRMWARE_IMAGE_DEP *Dependencies;\r
UINT32 DependenciesSize;\r
- BOOLEAN IsDepexValid;\r
- UINT8 *ImageBuffer;\r
- UINTN ImageBufferSize;\r
\r
Status = EFI_SUCCESS;\r
Updateable = 0;\r
LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
Dependencies = NULL;\r
DependenciesSize = 0;\r
- ImageBuffer = NULL;\r
- ImageBufferSize = 0;\r
\r
if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
return EFI_UNSUPPORTED;\r
goto cleanup;\r
}\r
\r
- //\r
- // Set check status to satisfied before CheckTheImage()\r
- //\r
- mDependenciesCheckStatus = DEPENDENCIES_SATISFIED;\r
-\r
//\r
// Call check image to verify the image\r
//\r
goto cleanup;\r
}\r
\r
+ //\r
+ // Get the dependency from Image.\r
+ //\r
+ Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize);\r
+\r
//\r
// No functional error in CheckTheImage. Attempt to get the Version to\r
// support better error reporting.\r
//\r
- FmpHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );\r
+ FmpHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, DependenciesSize, &FmpPayloadSize );\r
if (FmpHeader == NULL) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpHeader failed.\n", mImageIdName));\r
Status = EFI_ABORTED;\r
goto cleanup;\r
}\r
Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncomingFwVersion);\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Check if there is dependency expression\r
- //\r
- IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP*) FmpHeader, FmpPayloadSize, &DependenciesSize);\r
- if (IsDepexValid && (DependenciesSize < FmpPayloadSize)) {\r
- //\r
- // Fmp payload is after dependency expression\r
- //\r
- Dependencies = (EFI_FIRMWARE_IMAGE_DEP*) FmpHeader;\r
- FmpHeader = (UINT8 *) FmpHeader + DependenciesSize;\r
- FmpPayloadSize = FmpPayloadSize - DependenciesSize;\r
- Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncomingFwVersion);\r
- }\r
- }\r
if (!EFI_ERROR (Status)) {\r
//\r
// Set to actual value\r
"FmpDxe(%s): SetTheImage() - Check The Image returned that the Image was not valid for update. Updatable value = 0x%X.\n",\r
mImageIdName, Updateable)\r
);\r
- if (mDependenciesCheckStatus == DEPENDENCIES_UNSATISFIED) {\r
+ if (Private->DependenciesSatisfied == FALSE) {\r
LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSATISFIED_DEPENDENCIES;\r
- } else if (mDependenciesCheckStatus == DEPENDENCIES_INVALID) {\r
- LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
}\r
Status = EFI_ABORTED;\r
goto cleanup;\r
goto cleanup;\r
}\r
\r
- //\r
- // Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY\r
- //\r
- if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
- //\r
- // To support saving dependency, extend param "Image" of FmpDeviceSetImage() to\r
- // contain the dependency inside. FmpDeviceSetImage() is responsible for saving\r
- // the dependency which can be used for future dependency check.\r
- //\r
- ImageBufferSize = DependenciesSize + ImageSize - AllHeaderSize;\r
- ImageBuffer = AllocatePool (ImageBufferSize);\r
- if (ImageBuffer == NULL) {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - AllocatePool failed.\n", mImageIdName));\r
- Status = EFI_ABORTED;\r
- goto cleanup;\r
- }\r
- CopyMem (ImageBuffer, Dependencies->Dependencies, DependenciesSize);\r
- CopyMem (ImageBuffer + DependenciesSize, (UINT8 *)Image + AllHeaderSize, ImageBufferSize - DependenciesSize);\r
- } else {\r
- ImageBufferSize = ImageSize - AllHeaderSize;\r
- ImageBuffer = AllocateCopyPool(ImageBufferSize, (UINT8 *)Image + AllHeaderSize);\r
- if (ImageBuffer == NULL) {\r
- DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - AllocatePool failed.\n", mImageIdName));\r
- Status = EFI_ABORTED;\r
- goto cleanup;\r
- }\r
- }\r
-\r
//\r
// Indicate that control is handed off to FmpDeviceLib\r
//\r
//Copy the requested image to the firmware using the FmpDeviceLib\r
//\r
Status = FmpDeviceSetImage (\r
- ImageBuffer,\r
- ImageBufferSize,\r
+ (((UINT8 *)Image) + AllHeaderSize),\r
+ ImageSize - AllHeaderSize,\r
VendorCode,\r
FmpDxeProgress,\r
IncomingFwVersion,\r
goto cleanup;\r
}\r
\r
+ //\r
+ // Store the dependency\r
+ //\r
+ if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
+ Status = SaveFmpDependency (Dependencies, DependenciesSize);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() SaveFmpDependency from FmpDependencyCheckLib failed. (%r)\n", mImageIdName, Status));\r
+ }\r
+ Status = EFI_SUCCESS;\r
+ }\r
\r
//\r
// Finished the update without error\r
LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
\r
cleanup:\r
- if (ImageBuffer != NULL) {\r
- FreePool (ImageBuffer);\r
- }\r
-\r
mProgressFunc = NULL;\r
SetLastAttemptStatusInVariable (Private, LastAttemptStatus);\r
\r
#include <Library/FmpDeviceLib.h>\r
#include <Library/FmpPayloadHeaderLib.h>\r
#include <Library/CapsuleUpdatePolicyLib.h>\r
+#include <Library/FmpDependencyLib.h>\r
+#include <Library/FmpDependencyCheckLib.h>\r
+#include <Library/FmpDependencyDeviceLib.h>\r
#include <Protocol/FirmwareManagement.h>\r
#include <Protocol/FirmwareManagementProgress.h>\r
#include <Protocol/VariableLock.h>\r
CHAR16 *LastAttemptStatusVariableName;\r
CHAR16 *LastAttemptVersionVariableName;\r
CHAR16 *FmpStateVariableName;\r
+ BOOLEAN DependenciesSatisfied;\r
} FIRMWARE_MANAGEMENT_PRIVATE_DATA;\r
\r
///\r
[Sources]\r
FmpDxe.c\r
FmpDxe.h\r
- Dependency.c\r
- Dependency.h\r
DetectTestKey.c\r
VariableSupport.h\r
VariableSupport.c\r
FmpDeviceLib\r
FmpPayloadHeaderLib\r
CapsuleUpdatePolicyLib\r
+ FmpDependencyLib\r
+ FmpDependencyCheckLib\r
+ FmpDependencyDeviceLib\r
\r
[Guids]\r
gEfiEndOfDxeEventGroupGuid\r
[Sources]\r
FmpDxe.c\r
FmpDxe.h\r
- Dependency.c\r
- Dependency.h\r
DetectTestKey.c\r
VariableSupport.h\r
VariableSupport.c\r
FmpDeviceLib\r
FmpPayloadHeaderLib\r
CapsuleUpdatePolicyLib\r
+ FmpDependencyLib\r
+ FmpDependencyCheckLib\r
+ FmpDependencyDeviceLib\r
\r
[Guids]\r
gEfiEndOfDxeEventGroupGuid\r