information provided through PCDs and libraries.\r
\r
Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>\r
- Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\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
)\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
\r
if (Private->DescriptorPopulated) {\r
return;\r
Private->Descriptor.LastAttemptVersion = GetLastAttemptVersionFromVariable (Private);\r
Private->Descriptor.LastAttemptStatus = GetLastAttemptStatusFromVariable (Private);\r
\r
+ //\r
+ // Get the dependency from the FmpDeviceLib and populate it to the descriptor.\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 == TRUE) {\r
+ Private->Descriptor.Dependencies = AllocatePool (DepexSize);\r
+ if (Private->Descriptor.Dependencies != NULL) {\r
+ CopyMem (Private->Descriptor.Dependencies->Dependencies, Image, DepexSize);\r
+ }\r
+ }\r
+ }\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
+ Status = EFI_SUCCESS;\r
+ ImageBuffer = NULL;\r
+ DepexSize = 0;\r
\r
//\r
// Retrieve the private context structure\r
if (EFI_ERROR (Status)) {\r
Size = 0;\r
}\r
- if (*ImageSize < Size) {\r
- *ImageSize = Size;\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
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
- Status = FmpDeviceGetImage (Image, ImageSize);\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
cleanup:\r
+ if (ImageBuffer != NULL) {\r
+ FreePool (ImageBuffer);\r
+ }\r
\r
return Status;\r
}\r
UINTN PublicKeyDataLength;\r
UINT8 *PublicKeyDataXdr;\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
Version = 0;\r
FmpHeaderSize = 0;\r
AllHeaderSize = 0;\r
+ Dependencies = NULL;\r
+ DependenciesSize = 0;\r
\r
if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
return EFI_UNSUPPORTED;\r
}\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
+ // 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
}\r
\r
//\r
goto cleanup;\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
+ *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+ Status = EFI_SUCCESS;\r
+ goto cleanup;\r
+ }\r
+\r
//\r
// Get the FmpHeaderSize so we can determine the real payload size\r
//\r
// Call FmpDevice Lib Check Image on the\r
// Raw payload. So all headers need stripped off\r
//\r
- AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );\r
+ AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize);\r
if (AllHeaderSize == 0) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
Status = EFI_ABORTED;\r
UINT32 LastAttemptStatus;\r
UINT32 Version;\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
FmpHeader = NULL;\r
FmpPayloadSize = 0;\r
AllHeaderSize = 0;\r
- IncomingFwVersion = 0;\r
+ IncomingFwVersion = 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
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
+ 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
}\r
goto cleanup;\r
}\r
\r
- AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );\r
+ AllHeaderSize = GetAllHeaderSize ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize);\r
if (AllHeaderSize == 0) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
Status = EFI_ABORTED;\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
- (((UINT8 *)Image) + AllHeaderSize),\r
- ImageSize - AllHeaderSize,\r
+ ImageBuffer,\r
+ ImageBufferSize,\r
VendorCode,\r
FmpDxeProgress,\r
IncomingFwVersion,\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