FmpDevicePkg/FmpDxe: Use new Fmp dependency libraries

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2696

Remove the orginal Fmp Capsule Dependency implement, and use new
FmpDependencyLib, FmpDependencyCheckLib and FmpDependencyDeviceLib
APIs instead.
A platform can perform the dependency check in a platform specific
manner by implementing its own FmpDependencyCheckLib.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Signed-off-by: Wei6 Xu <wei6.xu@intel.com>
Reviewed-by: Sean Brogan <sean.brogan@microsoft.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
This commit is contained in:
Wei6 Xu 2020-05-12 13:33:54 +08:00 committed by mergify[bot]
parent ba86bb2c4d
commit 0f30087b9a
6 changed files with 64 additions and 948 deletions

View File

@ -1,679 +0,0 @@
/** @file
Supports Capsule Dependency Expression.
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "FmpDxe.h"
#include "Dependency.h"
//
// Define the initial size of the dependency expression evaluation stack
//
#define DEPEX_STACK_SIZE_INCREMENT 0x1000
//
// Type of stack element
//
typedef enum {
BooleanType,
VersionType
} ELEMENT_TYPE;
//
// Value of stack element
//
typedef union {
BOOLEAN Boolean;
UINT32 Version;
} ELEMENT_VALUE;
//
// Stack element used to evaluate dependency expressions
//
typedef struct {
ELEMENT_VALUE Value;
ELEMENT_TYPE Type;
} DEPEX_ELEMENT;
//
// Global variable used to support dependency evaluation
//
UINTN mNumberOfFmpInstance = 0;
EFI_FIRMWARE_IMAGE_DESCRIPTOR **mFmpImageInfoBuf = NULL;
//
// Indicates the status of dependency check, default value is DEPENDENCIES_SATISFIED.
//
UINT8 mDependenciesCheckStatus = DEPENDENCIES_SATISFIED;
//
// Global stack used to evaluate dependency expressions
//
DEPEX_ELEMENT *mDepexEvaluationStack = NULL;
DEPEX_ELEMENT *mDepexEvaluationStackEnd = NULL;
DEPEX_ELEMENT *mDepexEvaluationStackPointer = NULL;
/**
Grow size of the Depex stack
@retval EFI_SUCCESS Stack successfully growed.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
**/
EFI_STATUS
GrowDepexStack (
VOID
)
{
DEPEX_ELEMENT *NewStack;
UINTN Size;
Size = DEPEX_STACK_SIZE_INCREMENT;
if (mDepexEvaluationStack != NULL) {
Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
}
NewStack = AllocatePool (Size * sizeof (DEPEX_ELEMENT));
if (NewStack == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (mDepexEvaluationStack != NULL) {
//
// Copy to Old Stack to the New Stack
//
CopyMem (
NewStack,
mDepexEvaluationStack,
(mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (DEPEX_ELEMENT)
);
//
// Free The Old Stack
//
FreePool (mDepexEvaluationStack);
}
//
// Make the Stack pointer point to the old data in the new stack
//
mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
mDepexEvaluationStack = NewStack;
mDepexEvaluationStackEnd = NewStack + Size;
return EFI_SUCCESS;
}
/**
Push an element onto the Stack.
@param[in] Value Value to push.
@param[in] Type Element Type
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
@retval EFI_INVALID_PARAMETER Wrong stack element type.
**/
EFI_STATUS
Push (
IN UINT32 Value,
IN UINTN Type
)
{
EFI_STATUS Status;
DEPEX_ELEMENT Element;
//
// Check Type
//
if (Type != BooleanType && Type != VersionType) {
return EFI_INVALID_PARAMETER;
}
//
// Check for a stack overflow condition
//
if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
//
// Grow the stack
//
Status = GrowDepexStack ();
if (EFI_ERROR (Status)) {
return Status;
}
}
Element.Value.Version = Value;
Element.Type = Type;
//
// Push the item onto the stack
//
*mDepexEvaluationStackPointer = Element;
mDepexEvaluationStackPointer++;
return EFI_SUCCESS;
}
/**
Pop an element from the stack.
@param[out] Element Element to pop.
@param[in] Type Type of element.
@retval EFI_SUCCESS The value was popped onto the stack.
@retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
@retval EFI_INVALID_PARAMETER Type is mismatched.
**/
EFI_STATUS
Pop (
OUT DEPEX_ELEMENT *Element,
IN ELEMENT_TYPE Type
)
{
//
// Check for a stack underflow condition
//
if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
return EFI_ACCESS_DENIED;
}
//
// Pop the item off the stack
//
mDepexEvaluationStackPointer--;
*Element = *mDepexEvaluationStackPointer;
if ((*Element).Type != Type) {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
Evaluate the dependencies.
@param[in] Dependencies Dependency expressions.
@param[in] DependenciesSize Size of Dependency expressions.
@retval TRUE Dependency expressions evaluate to TRUE.
@retval FALSE Dependency expressions evaluate to FALSE.
**/
BOOLEAN
EvaluateDependencies (
IN CONST EFI_FIRMWARE_IMAGE_DEP * Dependencies,
IN CONST UINTN DependenciesSize
)
{
EFI_STATUS Status;
UINT8 *Iterator;
UINT8 Index;
DEPEX_ELEMENT Element1;
DEPEX_ELEMENT Element2;
GUID ImageTypeId;
UINT32 Version;
if (Dependencies == NULL || DependenciesSize == 0) {
return FALSE;
}
//
// Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
// incorrectly formed DEPEX expressions
//
mDepexEvaluationStackPointer = mDepexEvaluationStack;
Iterator = (UINT8 *) Dependencies->Dependencies;
while (Iterator < (UINT8 *) Dependencies->Dependencies + DependenciesSize) {
switch (*Iterator)
{
case EFI_FMP_DEP_PUSH_GUID:
if (Iterator + sizeof (EFI_GUID) >= (UINT8 *) Dependencies->Dependencies + DependenciesSize) {
Status = EFI_INVALID_PARAMETER;
goto Error;
}
CopyGuid (&ImageTypeId, (EFI_GUID *) (Iterator + 1));
Iterator = Iterator + sizeof (EFI_GUID);
for (Index = 0; Index < mNumberOfFmpInstance; Index ++){
if (mFmpImageInfoBuf[Index] == NULL) {
continue;
}
if(CompareGuid (&mFmpImageInfoBuf[Index]->ImageTypeId, &ImageTypeId)){
Status = Push (mFmpImageInfoBuf[Index]->Version, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
}
}
if (Index == mNumberOfFmpInstance) {
Status = EFI_NOT_FOUND;
goto Error;
}
break;
case EFI_FMP_DEP_PUSH_VERSION:
if (Iterator + sizeof (UINT32) >= (UINT8 *) Dependencies->Dependencies + DependenciesSize ) {
Status = EFI_INVALID_PARAMETER;
goto Error;
}
Version = *(UINT32 *) (Iterator + 1);
Status = Push (Version, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Iterator = Iterator + sizeof (UINT32);
break;
case EFI_FMP_DEP_VERSION_STR:
Iterator += AsciiStrnLenS ((CHAR8 *) Iterator, DependenciesSize - (Iterator - Dependencies->Dependencies));
break;
case EFI_FMP_DEP_AND:
Status = Pop (&Element1, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Pop (&Element2, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Push (Element1.Value.Boolean & Element2.Value.Boolean, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_OR:
Status = Pop (&Element1, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Pop(&Element2, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Push (Element1.Value.Boolean | Element2.Value.Boolean, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_NOT:
Status = Pop (&Element1, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Push (!(Element1.Value.Boolean), BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_TRUE:
Status = Push (TRUE, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_FALSE:
Status = Push (FALSE, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_EQ:
Status = Pop (&Element1, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Pop (&Element2, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = (Element1.Value.Version == Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_GT:
Status = Pop (&Element1, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Pop (&Element2, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = (Element1.Value.Version > Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_GTE:
Status = Pop (&Element1, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Pop (&Element2, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = (Element1.Value.Version >= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_LT:
Status = Pop (&Element1, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Pop (&Element2, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = (Element1.Value.Version < Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_LTE:
Status = Pop (&Element1, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = Pop (&Element2, VersionType);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = (Element1.Value.Version <= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
break;
case EFI_FMP_DEP_END:
Status = Pop (&Element1, BooleanType);
if (EFI_ERROR (Status)) {
goto Error;
}
return Element1.Value.Boolean;
default:
Status = EFI_INVALID_PARAMETER;
goto Error;
}
Iterator++;
}
Error:
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): EvaluateDependencies() - RESULT = FALSE (Status = %r)\n", mImageIdName, Status));
return FALSE;
}
/**
Validate the dependency expression and output its size.
@param[in] ImageDepex Pointer to the EFI_FIRMWARE_IMAGE_DEP.
@param[in] MaxDepexSize Max size of the dependency.
@param[out] DepexSize Size of dependency.
@retval TRUE The capsule is valid.
@retval FALSE The capsule is invalid.
**/
BOOLEAN
ValidateImageDepex (
IN EFI_FIRMWARE_IMAGE_DEP *ImageDepex,
IN CONST UINTN MaxDepexSize,
OUT UINT32 *DepexSize
)
{
UINT8 *Depex;
*DepexSize = 0;
Depex = ImageDepex->Dependencies;
while (Depex < ImageDepex->Dependencies + MaxDepexSize) {
switch (*Depex)
{
case EFI_FMP_DEP_PUSH_GUID:
Depex += sizeof (EFI_GUID) + 1;
break;
case EFI_FMP_DEP_PUSH_VERSION:
Depex += sizeof (UINT32) + 1;
break;
case EFI_FMP_DEP_VERSION_STR:
Depex += AsciiStrnLenS ((CHAR8 *) Depex, ImageDepex->Dependencies + MaxDepexSize - Depex) + 1;
break;
case EFI_FMP_DEP_AND:
case EFI_FMP_DEP_OR:
case EFI_FMP_DEP_NOT:
case EFI_FMP_DEP_TRUE:
case EFI_FMP_DEP_FALSE:
case EFI_FMP_DEP_EQ:
case EFI_FMP_DEP_GT:
case EFI_FMP_DEP_GTE:
case EFI_FMP_DEP_LT:
case EFI_FMP_DEP_LTE:
Depex += 1;
break;
case EFI_FMP_DEP_END:
Depex += 1;
*DepexSize = (UINT32)(Depex - ImageDepex->Dependencies);
return TRUE;
default:
return FALSE;
}
}
return FALSE;
}
/**
Get the size of dependencies. Assume the dependencies is validated before
calling this function.
@param[in] Dependencies Pointer to the EFI_FIRMWARE_IMAGE_DEP.
@retval The size of dependencies.
**/
UINTN
GetDepexSize (
IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies
)
{
UINTN Index;
if (Dependencies == NULL) {
return 0;
}
Index = 0;
while (Dependencies->Dependencies[Index] != EFI_FMP_DEP_END) {
Index ++;
}
return Index + 1;
}
/**
Check dependency for firmware update.
@param[in] ImageTypeId Image Type Id.
@param[in] Version New version.
@param[in] Dependencies The dependencies.
@param[in] DependenciesSize Size of the dependencies
@param[out] IsSatisfied Indicate the dependencies is satisfied or not.
@retval EFI_SUCCESS Dependency Evaluation is successful.
@retval Others Dependency Evaluation fails with unexpected error.
**/
EFI_STATUS
EvaluateImageDependencies (
IN CONST EFI_GUID ImageTypeId,
IN CONST UINT32 Version,
IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies,
IN CONST UINT32 DependenciesSize,
OUT BOOLEAN *IsSatisfied
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
UINTN ImageInfoSize;
UINT32 FmpImageInfoDescriptorVer;
UINT8 FmpImageInfoCount;
UINTN DescriptorSize;
UINT32 PackageVersion;
CHAR16 *PackageVersionName;
UINTN DepexSize;
*IsSatisfied = TRUE;
PackageVersionName = NULL;
//
// Get ImageDescriptors of all FMP instances, and archive them for depex evaluation.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareManagementProtocolGuid,
NULL,
&mNumberOfFmpInstance,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
mFmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * mNumberOfFmpInstance);
if (mFmpImageInfoBuf == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareManagementProtocolGuid,
(VOID **) &Fmp
);
if (EFI_ERROR(Status)) {
continue;
}
ImageInfoSize = 0;
Status = Fmp->GetImageInfo (
Fmp,
&ImageInfoSize,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
if (Status != EFI_BUFFER_TOO_SMALL) {
continue;
}
mFmpImageInfoBuf[Index] = AllocateZeroPool (ImageInfoSize);
if (mFmpImageInfoBuf[Index] == NULL) {
continue;
}
Status = Fmp->GetImageInfo (
Fmp,
&ImageInfoSize, // ImageInfoSize
mFmpImageInfoBuf[Index], // ImageInfo
&FmpImageInfoDescriptorVer, // DescriptorVersion
&FmpImageInfoCount, // DescriptorCount
&DescriptorSize, // DescriptorSize
&PackageVersion, // PackageVersion
&PackageVersionName // PackageVersionName
);
if (EFI_ERROR(Status)) {
FreePool (mFmpImageInfoBuf[Index]);
mFmpImageInfoBuf[Index] = NULL;
continue;
}
if (PackageVersionName != NULL) {
FreePool (PackageVersionName);
PackageVersionName = NULL;
}
}
//
// Step 1 - Evaluate firmware image's depex, against the version of other Fmp instances.
//
if (Dependencies != NULL) {
*IsSatisfied = EvaluateDependencies (Dependencies, DependenciesSize);
}
if (!*IsSatisfied) {
goto cleanup;
}
//
// Step 2 - Evaluate the depex of all other Fmp instances, against the new version in
// the firmware image.
//
//
// Update the new version to mFmpImageInfoBuf.
//
for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {
if (mFmpImageInfoBuf[Index] != NULL) {
if (CompareGuid (&ImageTypeId, &mFmpImageInfoBuf[Index]->ImageTypeId)) {
mFmpImageInfoBuf[Index]->Version = Version;
break;
}
}
}
//
// Evaluate the Dependencies one by one.
//
for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {
if (mFmpImageInfoBuf[Index] != NULL) {
//
// Skip the Fmp instance to be "SetImage".
//
if (CompareGuid (&ImageTypeId, &mFmpImageInfoBuf[Index]->ImageTypeId)) {
continue;
}
if ((mFmpImageInfoBuf[Index]->AttributesSupported & IMAGE_ATTRIBUTE_DEPENDENCY) &&
mFmpImageInfoBuf[Index]->Dependencies != NULL) {
//
// Get the size of depex.
// Assume that the dependencies in EFI_FIRMWARE_IMAGE_DESCRIPTOR is validated when PopulateDescriptor().
//
DepexSize = GetDepexSize (mFmpImageInfoBuf[Index]->Dependencies);
if (DepexSize > 0) {
*IsSatisfied = EvaluateDependencies (mFmpImageInfoBuf[Index]->Dependencies, DepexSize);
if (!*IsSatisfied) {
break;
}
}
}
}
}
cleanup:
if (mFmpImageInfoBuf != NULL) {
for (Index = 0; Index < mNumberOfFmpInstance; Index ++) {
if (mFmpImageInfoBuf[Index] != NULL) {
FreePool (mFmpImageInfoBuf[Index]);
}
}
FreePool (mFmpImageInfoBuf);
}
return EFI_SUCCESS;
}

View File

@ -1,63 +0,0 @@
/** @file
Fmp Capsule Dependency support functions for Firmware Management Protocol based
firmware updates.
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __DEPENDENCY_H__
#define __DEPENDENCY_H__
#include <Library/UefiLib.h>
#include <Protocol/FirmwareManagement.h>
#define DEPENDENCIES_SATISFIED 0
#define DEPENDENCIES_UNSATISFIED 1
#define DEPENDENCIES_INVALID 2
extern UINT8 mDependenciesCheckStatus;
/**
Validate the dependency expression and output its size.
@param[in] ImageDepex Pointer to the EFI_FIRMWARE_IMAGE_DEP.
@param[in] MaxDepexSize Max size of the dependency.
@param[out] DepexSize Size of dependency.
@retval TRUE The capsule is valid.
@retval FALSE The capsule is invalid.
**/
BOOLEAN
ValidateImageDepex (
IN EFI_FIRMWARE_IMAGE_DEP *ImageDepex,
IN CONST UINTN MaxDepexSize,
OUT UINT32 *DepexSize
);
/**
Check dependency for firmware update.
@param[in] ImageTypeId Image Type Id.
@param[in] Version New version.
@param[in] Dependencies The dependencies.
@param[in] DepexSize Size of the dependencies
@param[out] IsSatisfied Indicate the dependencies is satisfied or not.
@retval EFI_SUCCESS Dependency Evaluation is successful.
@retval Others Dependency Evaluation fails with unexpected error.
**/
EFI_STATUS
EvaluateImageDependencies (
IN CONST EFI_GUID ImageTypeId,
IN CONST UINT32 Version,
IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies,
IN CONST UINT32 DepexSize,
OUT BOOLEAN *IsSatisfied
);
#endif

View File

@ -12,7 +12,6 @@
#include "FmpDxe.h"
#include "VariableSupport.h"
#include "Dependency.h"
///
/// FILE_GUID from FmpDxe.inf. When FmpDxe.inf is used in a platform, the
@ -81,7 +80,8 @@ const FIRMWARE_MANAGEMENT_PRIVATE_DATA mFirmwareManagementPrivateDataTemplate =
NULL, // LsvVariableName
NULL, // LastAttemptStatusVariableName
NULL, // LastAttemptVersionVariableName
NULL // FmpStateVariableName
NULL, // FmpStateVariableName
TRUE // DependenciesSatisfied
};
///
@ -276,13 +276,7 @@ PopulateDescriptor (
)
{
EFI_STATUS Status;
VOID *Image;
UINTN ImageSize;
BOOLEAN IsDepexValid;
UINT32 DepexSize;
Image = NULL;
ImageSize = 0;
UINT32 DependenciesSize;
if (Private->DescriptorPopulated) {
return;
@ -387,46 +381,18 @@ PopulateDescriptor (
Private->Descriptor.LastAttemptStatus = GetLastAttemptStatusFromVariable (Private);
//
// Get the dependency from the FmpDeviceLib and populate it to the descriptor.
// Get the dependency from the FmpDependencyDeviceLib.
//
Private->Descriptor.Dependencies = NULL;
//
// Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY
//
if (Private->Descriptor.AttributesSupported & IMAGE_ATTRIBUTE_DEPENDENCY) {
//
// The parameter "Image" of FmpDeviceGetImage() is extended to contain the dependency.
// Get the dependency from the Image.
//
ImageSize = Private->Descriptor.Size;
Image = AllocatePool (ImageSize);
if (Image != NULL) {
Status = FmpDeviceGetImage (Image, &ImageSize);
if (Status == EFI_BUFFER_TOO_SMALL) {
FreePool (Image);
Image = AllocatePool (ImageSize);
if (Image != NULL) {
Status = FmpDeviceGetImage (Image, &ImageSize);
}
}
}
if (!EFI_ERROR (Status) && Image != NULL) {
IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP *) Image, ImageSize, &DepexSize);
if (IsDepexValid) {
Private->Descriptor.Dependencies = AllocatePool (DepexSize);
if (Private->Descriptor.Dependencies != NULL) {
CopyMem (Private->Descriptor.Dependencies->Dependencies, Image, DepexSize);
}
}
}
if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {
Private->Descriptor.Dependencies = GetFmpDependency (&DependenciesSize);
}
Private->DescriptorPopulated = TRUE;
if (Image != NULL) {
FreePool (Image);
}
}
/**
@ -588,17 +554,12 @@ GetTheImage (
EFI_STATUS Status;
FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private;
UINTN Size;
UINT8 *ImageBuffer;
UINTN ImageBufferSize;
UINT32 DepexSize;
if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {
return EFI_UNSUPPORTED;
}
Status = EFI_SUCCESS;
ImageBuffer = NULL;
DepexSize = 0;
Status = EFI_SUCCESS;
//
// Retrieve the private context structure
@ -628,45 +589,8 @@ GetTheImage (
if (EFI_ERROR (Status)) {
Size = 0;
}
//
// The parameter "Image" of FmpDeviceGetImage() is extended to contain the dependency.
// Get the Fmp Payload from the Image.
//
ImageBufferSize = Size;
ImageBuffer = AllocatePool (ImageBufferSize);
if (ImageBuffer == NULL) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - AllocatePool fails.\n", mImageIdName));
Status = EFI_NOT_FOUND;
goto cleanup;
}
Status = FmpDeviceGetImage (ImageBuffer, &ImageBufferSize);
if (Status == EFI_BUFFER_TOO_SMALL) {
FreePool (ImageBuffer);
ImageBuffer = AllocatePool (ImageBufferSize);
if (ImageBuffer == NULL) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - AllocatePool fails.\n", mImageIdName));
Status = EFI_NOT_FOUND;
goto cleanup;
}
Status = FmpDeviceGetImage (ImageBuffer, &ImageBufferSize);
}
if (EFI_ERROR (Status)) {
goto cleanup;
}
//
// Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY
//
if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {
//
// Validate the dependency to get its size.
//
ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP *) ImageBuffer, ImageBufferSize, &DepexSize);
}
if (*ImageSize < ImageBufferSize - DepexSize) {
*ImageSize = ImageBufferSize - DepexSize;
if (*ImageSize < Size) {
*ImageSize = Size;
DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImage() - ImageSize is to small.\n", mImageIdName));
Status = EFI_BUFFER_TOO_SMALL;
goto cleanup;
@ -678,17 +602,8 @@ GetTheImage (
goto cleanup;
}
//
// Image is after the dependency expression.
//
*ImageSize = ImageBufferSize - DepexSize;
CopyMem (Image, ImageBuffer + DepexSize, *ImageSize);
Status = EFI_SUCCESS;
Status = FmpDeviceGetImage (Image, ImageSize);
cleanup:
if (ImageBuffer != NULL) {
FreePool (ImageBuffer);
}
return Status;
}
@ -697,8 +612,9 @@ cleanup:
Helper function to safely retrieve the FMP header from
within an EFI_FIRMWARE_IMAGE_AUTHENTICATION structure.
@param[in] Image Pointer to the image.
@param[in] ImageSize Size of the image.
@param[in] Image Pointer to the image.
@param[in] ImageSize Size of the image.
@param[in] AdditionalHeaderSize Size of any headers that cannot be calculated by this function.
@param[out] PayloadSize
@retval !NULL Valid pointer to the header.
@ -709,22 +625,23 @@ VOID *
GetFmpHeader (
IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
IN CONST UINTN ImageSize,
IN CONST UINTN AdditionalHeaderSize,
OUT UINTN *PayloadSize
)
{
//
// Check to make sure that operation can be safely performed.
//
if (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) < (UINTN)Image || \
((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize) {
if (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) + AdditionalHeaderSize < (UINTN)Image || \
((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) + AdditionalHeaderSize >= (UINTN)Image + ImageSize) {
//
// Pointer overflow. Invalid image.
//
return NULL;
}
*PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
*PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength + AdditionalHeaderSize);
return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength + AdditionalHeaderSize);
}
/**
@ -811,8 +728,6 @@ CheckTheImage (
UINT8 *PublicKeyDataXdrEnd;
EFI_FIRMWARE_IMAGE_DEP *Dependencies;
UINT32 DependenciesSize;
BOOLEAN IsDepexValid;
BOOLEAN IsDepexSatisfied;
Status = EFI_SUCCESS;
RawSize = 0;
@ -850,6 +765,11 @@ CheckTheImage (
//
*ImageUpdatable = IMAGE_UPDATABLE_VALID;
//
// Set to satisfied and then if dependency evaluates to false it will update this flag.
//
Private->DependenciesSatisfied = TRUE;
if (Image == NULL) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Pointer Parameter is NULL.\n", mImageIdName));
//
@ -935,11 +855,15 @@ CheckTheImage (
goto cleanup;
}
//
// Get the dependency from Image.
//
Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize);
//
// Check the FmpPayloadHeader
//
FmpPayloadHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );
FmpPayloadHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, DependenciesSize, &FmpPayloadSize );
if (FmpPayloadHeader == NULL) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpHeader failed.\n", mImageIdName));
Status = EFI_ABORTED;
@ -947,33 +871,10 @@ CheckTheImage (
}
Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);
if (EFI_ERROR (Status)) {
//
// Check if there is dependency expression
//
IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP*) FmpPayloadHeader, FmpPayloadSize, &DependenciesSize);
if (IsDepexValid && (DependenciesSize < FmpPayloadSize)) {
//
// Fmp payload is after dependency expression
//
Dependencies = (EFI_FIRMWARE_IMAGE_DEP*) FmpPayloadHeader;
FmpPayloadHeader = (UINT8 *) Dependencies + DependenciesSize;
FmpPayloadSize = FmpPayloadSize - DependenciesSize;
Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));
*ImageUpdatable = IMAGE_UPDATABLE_INVALID;
Status = EFI_SUCCESS;
goto cleanup;
}
} else {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency is invalid.\n", mImageIdName));
mDependenciesCheckStatus = DEPENDENCIES_INVALID;
*ImageUpdatable = IMAGE_UPDATABLE_INVALID;
Status = EFI_SUCCESS;
goto cleanup;
}
} else {
DEBUG ((DEBUG_WARN, "FmpDxe(%s): CheckTheImage() - No dependency associated in image.\n", mImageIdName));
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));
*ImageUpdatable = IMAGE_UPDATABLE_INVALID;
Status = EFI_SUCCESS;
goto cleanup;
}
//
@ -993,14 +894,9 @@ CheckTheImage (
//
// Evaluate dependency expression
//
Status = EvaluateImageDependencies (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize, &IsDepexSatisfied);
if (!IsDepexSatisfied || EFI_ERROR (Status)) {
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed %r.\n", mImageIdName, Status));
} else {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency is not satisfied.\n", mImageIdName));
}
mDependenciesCheckStatus = DEPENDENCIES_UNSATISFIED;
Private->DependenciesSatisfied = CheckFmpDependency (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize);
if (!Private->DependenciesSatisfied) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed.\n", mImageIdName));
*ImageUpdatable = IMAGE_UPDATABLE_INVALID;
Status = EFI_SUCCESS;
goto cleanup;
@ -1113,9 +1009,6 @@ SetTheImage (
UINT32 LowestSupportedVersion;
EFI_FIRMWARE_IMAGE_DEP *Dependencies;
UINT32 DependenciesSize;
BOOLEAN IsDepexValid;
UINT8 *ImageBuffer;
UINTN ImageBufferSize;
Status = EFI_SUCCESS;
Updateable = 0;
@ -1128,8 +1021,6 @@ SetTheImage (
LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
Dependencies = NULL;
DependenciesSize = 0;
ImageBuffer = NULL;
ImageBufferSize = 0;
if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {
return EFI_UNSUPPORTED;
@ -1161,11 +1052,6 @@ SetTheImage (
goto cleanup;
}
//
// Set check status to satisfied before CheckTheImage()
//
mDependenciesCheckStatus = DEPENDENCIES_SATISFIED;
//
// Call check image to verify the image
//
@ -1178,32 +1064,22 @@ SetTheImage (
goto cleanup;
}
//
// Get the dependency from Image.
//
Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize);
//
// No functional error in CheckTheImage. Attempt to get the Version to
// support better error reporting.
//
FmpHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );
FmpHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, DependenciesSize, &FmpPayloadSize );
if (FmpHeader == NULL) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpHeader failed.\n", mImageIdName));
Status = EFI_ABORTED;
goto cleanup;
}
Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncomingFwVersion);
if (EFI_ERROR (Status)) {
//
// Check if there is dependency expression
//
IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP*) FmpHeader, FmpPayloadSize, &DependenciesSize);
if (IsDepexValid && (DependenciesSize < FmpPayloadSize)) {
//
// Fmp payload is after dependency expression
//
Dependencies = (EFI_FIRMWARE_IMAGE_DEP*) FmpHeader;
FmpHeader = (UINT8 *) FmpHeader + DependenciesSize;
FmpPayloadSize = FmpPayloadSize - DependenciesSize;
Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncomingFwVersion);
}
}
if (!EFI_ERROR (Status)) {
//
// Set to actual value
@ -1218,10 +1094,8 @@ SetTheImage (
"FmpDxe(%s): SetTheImage() - Check The Image returned that the Image was not valid for update. Updatable value = 0x%X.\n",
mImageIdName, Updateable)
);
if (mDependenciesCheckStatus == DEPENDENCIES_UNSATISFIED) {
if (Private->DependenciesSatisfied == FALSE) {
LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSATISFIED_DEPENDENCIES;
} else if (mDependenciesCheckStatus == DEPENDENCIES_INVALID) {
LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
}
Status = EFI_ABORTED;
goto cleanup;
@ -1323,34 +1197,6 @@ SetTheImage (
goto cleanup;
}
//
// Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY
//
if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {
//
// To support saving dependency, extend param "Image" of FmpDeviceSetImage() to
// contain the dependency inside. FmpDeviceSetImage() is responsible for saving
// the dependency which can be used for future dependency check.
//
ImageBufferSize = DependenciesSize + ImageSize - AllHeaderSize;
ImageBuffer = AllocatePool (ImageBufferSize);
if (ImageBuffer == NULL) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - AllocatePool failed.\n", mImageIdName));
Status = EFI_ABORTED;
goto cleanup;
}
CopyMem (ImageBuffer, Dependencies->Dependencies, DependenciesSize);
CopyMem (ImageBuffer + DependenciesSize, (UINT8 *)Image + AllHeaderSize, ImageBufferSize - DependenciesSize);
} else {
ImageBufferSize = ImageSize - AllHeaderSize;
ImageBuffer = AllocateCopyPool(ImageBufferSize, (UINT8 *)Image + AllHeaderSize);
if (ImageBuffer == NULL) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - AllocatePool failed.\n", mImageIdName));
Status = EFI_ABORTED;
goto cleanup;
}
}
//
// Indicate that control is handed off to FmpDeviceLib
//
@ -1360,8 +1206,8 @@ SetTheImage (
//Copy the requested image to the firmware using the FmpDeviceLib
//
Status = FmpDeviceSetImage (
ImageBuffer,
ImageBufferSize,
(((UINT8 *)Image) + AllHeaderSize),
ImageSize - AllHeaderSize,
VendorCode,
FmpDxeProgress,
IncomingFwVersion,
@ -1372,6 +1218,16 @@ SetTheImage (
goto cleanup;
}
//
// Store the dependency
//
if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {
Status = SaveFmpDependency (Dependencies, DependenciesSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() SaveFmpDependency from FmpDependencyCheckLib failed. (%r)\n", mImageIdName, Status));
}
Status = EFI_SUCCESS;
}
//
// Finished the update without error
@ -1398,10 +1254,6 @@ SetTheImage (
LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
cleanup:
if (ImageBuffer != NULL) {
FreePool (ImageBuffer);
}
mProgressFunc = NULL;
SetLastAttemptStatusInVariable (Private, LastAttemptStatus);

View File

@ -28,6 +28,9 @@
#include <Library/FmpDeviceLib.h>
#include <Library/FmpPayloadHeaderLib.h>
#include <Library/CapsuleUpdatePolicyLib.h>
#include <Library/FmpDependencyLib.h>
#include <Library/FmpDependencyCheckLib.h>
#include <Library/FmpDependencyDeviceLib.h>
#include <Protocol/FirmwareManagement.h>
#include <Protocol/FirmwareManagementProgress.h>
#include <Protocol/VariableLock.h>
@ -66,6 +69,7 @@ typedef struct {
CHAR16 *LastAttemptStatusVariableName;
CHAR16 *LastAttemptVersionVariableName;
CHAR16 *FmpStateVariableName;
BOOLEAN DependenciesSatisfied;
} FIRMWARE_MANAGEMENT_PRIVATE_DATA;
///

View File

@ -28,8 +28,6 @@
[Sources]
FmpDxe.c
FmpDxe.h
Dependency.c
Dependency.h
DetectTestKey.c
VariableSupport.h
VariableSupport.c
@ -54,6 +52,9 @@
FmpDeviceLib
FmpPayloadHeaderLib
CapsuleUpdatePolicyLib
FmpDependencyLib
FmpDependencyCheckLib
FmpDependencyDeviceLib
[Guids]
gEfiEndOfDxeEventGroupGuid

View File

@ -29,8 +29,6 @@
[Sources]
FmpDxe.c
FmpDxe.h
Dependency.c
Dependency.h
DetectTestKey.c
VariableSupport.h
VariableSupport.c
@ -54,6 +52,9 @@
FmpDeviceLib
FmpPayloadHeaderLib
CapsuleUpdatePolicyLib
FmpDependencyLib
FmpDependencyCheckLib
FmpDependencyDeviceLib
[Guids]
gEfiEndOfDxeEventGroupGuid