image stored in a firmware device with platform and firmware device specific\r
information provided through PCDs and libraries.\r
\r
- Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>\r
+ Copyright (c) Microsoft Corporation.<BR>\r
Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
\r
SPDX-License-Identifier: BSD-2-Clause-Patent\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
if (ImageTypeIdGuidSize == sizeof (EFI_GUID)) {\r
FmpDeviceLibGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceImageTypeIdGuid);\r
} else {\r
- DEBUG ((DEBUG_INFO, "FmpDxe(%s): Fall back to ImageTypeIdGuid of gEfiCallerIdGuid\n", mImageIdName));\r
+ DEBUG ((DEBUG_WARN, "FmpDxe(%s): Fall back to ImageTypeIdGuid of gEfiCallerIdGuid\n", mImageIdName));\r
FmpDeviceLibGuid = &gEfiCallerIdGuid;\r
}\r
}\r
)\r
{\r
EFI_STATUS Status;\r
- VOID *Image;\r
- UINTN ImageSize;\r
- BOOLEAN IsDepexValid;\r
- UINT32 DepexSize;\r
+ UINT32 DependenciesSize;\r
\r
- Image = NULL;\r
- ImageSize = 0;\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): PopulateDescriptor() - Private is NULL.\n", mImageIdName));\r
+ return;\r
+ }\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
\r
Status = EFI_SUCCESS;\r
\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImageInfo() - This is NULL.\n", mImageIdName));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto cleanup;\r
+ }\r
+\r
//\r
// Retrieve the private context structure\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
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - This is NULL.\n", mImageIdName));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto cleanup;\r
+ }\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[out] PayloadSize\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 An optional pointer to a UINTN that holds the size of the payload\r
+ (image size minus headers)\r
\r
@retval !NULL Valid pointer to the header.\r
@retval NULL Structure is bad and pointer cannot be found.\r
GetFmpHeader (\r
IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,\r
IN CONST UINTN ImageSize,\r
- OUT UINTN *PayloadSize\r
+ IN CONST UINTN AdditionalHeaderSize,\r
+ OUT UINTN *PayloadSize OPTIONAL\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
+ if (PayloadSize != NULL) {\r
+ *PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength + AdditionalHeaderSize);\r
+ }\r
+\r
+ return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength + AdditionalHeaderSize);\r
}\r
\r
/**\r
{\r
UINT32 CalculatedSize;\r
\r
+ if (Image == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetAllHeaderSize() - Image is NULL.\n", mImageIdName));\r
+ return 0;\r
+ }\r
+\r
CalculatedSize = sizeof (Image->MonotonicCount) +\r
AdditionalHeaderSize +\r
Image->AuthInfo.Hdr.dwLength;\r
@param[in] ImageSize Size of the new image in bytes.\r
@param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides,\r
if available, additional information if the image is invalid.\r
+ @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt status to report\r
+ back to the ESRT table in case of error. If an error does not occur,\r
+ this function will set the value to LAST_ATTEMPT_STATUS_SUCCESS.\r
+\r
+ This function will return error codes that occur within this function\r
+ implementation within a driver range of last attempt error codes from\r
+ LAST_ATTEMPT_STATUS_DRIVER_MIN_ERROR_CODE_VALUE\r
+ to LAST_ATTEMPT_STATUS_DRIVER_MAX_ERROR_CODE_VALUE.\r
+\r
+ This function might also return error codes that occur within libraries\r
+ linked against this module that return last attempt error codes such as:\r
+\r
+ LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MIN_ERROR_CODE_VALUE to\r
+ LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_LIB_MAX_ERROR_CODE_VALUE\r
+\r
+ LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MIN_ERROR_CODE_VALUE to\r
+ LAST_ATTEMPT_STATUS_FMP_DEPENDENCY_CHECK_LIB_MAX_ERROR_CODE_VALUE\r
\r
@retval EFI_SUCCESS The image was successfully checked.\r
@retval EFI_ABORTED The operation is aborted.\r
**/\r
EFI_STATUS\r
EFIAPI\r
-CheckTheImage (\r
+CheckTheImageInternal (\r
IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,\r
IN UINT8 ImageIndex,\r
IN CONST VOID *Image,\r
IN UINTN ImageSize,\r
- OUT UINT32 *ImageUpdatable\r
+ OUT UINT32 *ImageUpdatable,\r
+ OUT UINT32 *LastAttemptStatus\r
)\r
{\r
EFI_STATUS Status;\r
+ UINT32 LocalLastAttemptStatus;\r
FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private;\r
UINTN RawSize;\r
VOID *FmpPayloadHeader;\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
- FmpPayloadHeader = NULL;\r
- FmpPayloadSize = 0;\r
- Version = 0;\r
- FmpHeaderSize = 0;\r
- AllHeaderSize = 0;\r
- Dependencies = NULL;\r
- DependenciesSize = 0;\r
+\r
+ Status = EFI_SUCCESS;\r
+ LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+ RawSize = 0;\r
+ FmpPayloadHeader = NULL;\r
+ FmpPayloadSize = 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
\r
+ if (LastAttemptStatus == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImageInternal() - LastAttemptStatus is NULL.\n", mImageIdName));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto cleanup;\r
+ }\r
+\r
+ //\r
+ // A last attempt status error code will always override the success\r
+ // value before returning from the function\r
+ //\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - This is NULL.\n", mImageIdName));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_PROTOCOL_ARG_MISSING;\r
+ goto cleanup;\r
+ }\r
+\r
//\r
// Retrieve the private context structure\r
//\r
if (ImageUpdatable == NULL) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n", mImageIdName));\r
Status = EFI_INVALID_PARAMETER;\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_IMAGE_NOT_UPDATABLE;\r
goto cleanup;\r
}\r
\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
// not sure if this is needed\r
//\r
*ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_IMAGE_NOT_PROVIDED;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
if (PublicKeyDataXdr == NULL || (PublicKeyDataXdr == PublicKeyDataXdrEnd)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Invalid certificate, skipping it.\n", mImageIdName));\r
Status = EFI_ABORTED;\r
+ LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_CERTIFICATE;\r
} else {\r
//\r
// Try each key from PcdFmpDevicePkcs7CertBufferXdr\r
//\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate size extends beyond end of PCD, skipping it.\n", mImageIdName));\r
Status = EFI_ABORTED;\r
+ LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_KEY_LENGTH_VALUE;\r
break;\r
}\r
//\r
//\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate extends beyond end of PCD, skipping it.\n", mImageIdName));\r
Status = EFI_ABORTED;\r
+ LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_KEY_LENGTH;\r
break;\r
}\r
PublicKeyData = PublicKeyDataXdr;\r
\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Authentication Failed %r.\n", mImageIdName, Status));\r
+ if (LocalLastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) {\r
+ *LastAttemptStatus = LocalLastAttemptStatus;\r
+ } else {\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_IMAGE_AUTH_FAILURE;\r
+ }\r
goto cleanup;\r
}\r
\r
if (ImageIndex != 1) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Index Invalid.\n", mImageIdName));\r
*ImageUpdatable = IMAGE_UPDATABLE_INVALID_TYPE;\r
- Status = EFI_SUCCESS;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_INVALID_IMAGE_INDEX;\r
goto cleanup;\r
}\r
\r
+ //\r
+ // Get the dependency from Image.\r
+ //\r
+ Dependencies = GetImageDependency (\r
+ (EFI_FIRMWARE_IMAGE_AUTHENTICATION *) Image,\r
+ ImageSize,\r
+ &DependenciesSize,\r
+ LastAttemptStatus\r
+ );\r
+ if (*LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS) {\r
+ Status = EFI_ABORTED;\r
+ goto cleanup;\r
+ }\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
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER;\r
goto cleanup;\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
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER_VERSION;\r
+ goto cleanup;\r
}\r
\r
//\r
);\r
*ImageUpdatable = IMAGE_UPDATABLE_INVALID_OLD;\r
Status = EFI_SUCCESS;\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_VERSION_TOO_LOW;\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
+ Private->DependenciesSatisfied = CheckFmpDependency (\r
+ Private->Descriptor.ImageTypeId,\r
+ Version,\r
+ Dependencies,\r
+ DependenciesSize,\r
+ &LocalLastAttemptStatus\r
+ );\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
+ *LastAttemptStatus = LocalLastAttemptStatus;\r
goto cleanup;\r
}\r
\r
DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpPayloadHeaderSize failed %r.\n", Status));\r
*ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
Status = EFI_SUCCESS;\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER_SIZE;\r
goto cleanup;\r
}\r
\r
if (AllHeaderSize == 0) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
Status = EFI_ABORTED;\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_ALL_HEADER_SIZE;\r
goto cleanup;\r
}\r
RawSize = ImageSize - AllHeaderSize;\r
//\r
// FmpDeviceLib CheckImage function to do any specific checks\r
//\r
- Status = FmpDeviceCheckImage ((((UINT8 *)Image) + AllHeaderSize), RawSize, ImageUpdatable);\r
+ Status = FmpDeviceCheckImageWithStatus ((((UINT8 *) Image) + AllHeaderSize), RawSize, ImageUpdatable, LastAttemptStatus);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - FmpDeviceLib CheckImage failed. Status = %r\n", mImageIdName, Status));\r
+\r
+ //\r
+ // LastAttemptStatus returned from the device library should fall within the designated error range\r
+ // [LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE, LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE]\r
+ //\r
+ if ((*LastAttemptStatus < LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE) ||\r
+ (*LastAttemptStatus > LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE)) {\r
+ DEBUG (\r
+ (DEBUG_ERROR,\r
+ "FmpDxe(%s): CheckTheImage() - LastAttemptStatus %d from FmpDeviceCheckImageWithStatus() is invalid.\n",\r
+ mImageIdName,\r
+ *LastAttemptStatus)\r
+ );\r
+ *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+ }\r
}\r
\r
cleanup:\r
return Status;\r
}\r
\r
+/**\r
+ Checks if the firmware image is valid for the device.\r
+\r
+ This function allows firmware update application to validate the firmware image without\r
+ invoking the SetImage() first.\r
+\r
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.\r
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.\r
+ The number is between 1 and DescriptorCount.\r
+ @param[in] Image Points to the new image.\r
+ @param[in] ImageSize Size of the new image in bytes.\r
+ @param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides,\r
+ if available, additional information if the image is invalid.\r
+\r
+ @retval EFI_SUCCESS The image was successfully checked.\r
+ @retval EFI_ABORTED The operation is aborted.\r
+ @retval EFI_INVALID_PARAMETER The Image was NULL.\r
+ @retval EFI_UNSUPPORTED The operation is not supported.\r
+ @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CheckTheImage (\r
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,\r
+ IN UINT8 ImageIndex,\r
+ IN CONST VOID *Image,\r
+ IN UINTN ImageSize,\r
+ OUT UINT32 *ImageUpdatable\r
+ )\r
+{\r
+ UINT32 LastAttemptStatus;\r
+\r
+ return CheckTheImageInternal (This, ImageIndex, Image, ImageSize, ImageUpdatable, &LastAttemptStatus);\r
+}\r
+\r
/**\r
Updates the firmware image of the device.\r
\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
+ Private = NULL;\r
Updateable = 0;\r
BooleanValue = FALSE;\r
FmpHeaderSize = 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
}\r
\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - This is NULL.\n", mImageIdName));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_PROTOCOL_ARG_MISSING;\r
+ goto cleanup;\r
+ }\r
+\r
//\r
// Retrieve the private context structure\r
//\r
//\r
if (Private->FmpDeviceLocked) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Device is already locked. Can't update.\n", mImageIdName));\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_DEVICE_LOCKED;\r
Status = 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
- Status = CheckTheImage (This, ImageIndex, Image, ImageSize, &Updateable);\r
+ Status = CheckTheImageInternal (This, ImageIndex, Image, ImageSize, &Updateable, &LastAttemptStatus);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Check The Image failed with %r.\n", mImageIdName, Status));\r
- if (Status == EFI_SECURITY_VIOLATION) {\r
- LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
- }\r
goto cleanup;\r
}\r
\r
+ //\r
+ // Get the dependency from Image.\r
+ //\r
+ Dependencies = GetImageDependency ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize, &LastAttemptStatus);\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
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER;\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
\r
if (Progress == NULL) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Invalid progress callback\n", mImageIdName));\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_PROGRESS_CALLBACK_ERROR;\r
Status = EFI_INVALID_PARAMETER;\r
goto cleanup;\r
}\r
Status = CheckSystemPower (&BooleanValue);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemPower - API call failed %r.\n", mImageIdName, Status));\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_CHECK_POWER_API;\r
goto cleanup;\r
}\r
if (!BooleanValue) {\r
Status = CheckSystemThermal (&BooleanValue);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemThermal - API call failed %r.\n", mImageIdName, Status));\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_CHECK_SYS_THERMAL_API;\r
goto cleanup;\r
}\r
if (!BooleanValue) {\r
Status = EFI_ABORTED;\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_THERMAL;\r
DEBUG (\r
(DEBUG_ERROR,\r
"FmpDxe(%s): SetTheImage() - CheckSystemThermal - returned False. Update not allowed due to System Thermal.\n", mImageIdName)\r
Status = CheckSystemEnvironment (&BooleanValue);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - API call failed %r.\n", mImageIdName, Status));\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_CHECK_SYS_ENV_API;\r
goto cleanup;\r
}\r
if (!BooleanValue) {\r
Status = EFI_ABORTED;\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_SYSTEM_ENV;\r
DEBUG (\r
(DEBUG_ERROR,\r
"FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - returned False. Update not allowed due to System Environment.\n", mImageIdName)\r
Status = GetFmpPayloadHeaderSize (FmpHeader, FmpPayloadSize, &FmpHeaderSize);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpPayloadHeaderSize failed %r.\n", mImageIdName, Status));\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_FMP_HEADER_SIZE;\r
goto cleanup;\r
}\r
\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
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_DRIVER_ERROR_GET_ALL_HEADER_SIZE;\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
//\r
//Copy the requested image to the firmware using the FmpDeviceLib\r
//\r
- Status = FmpDeviceSetImage (\r
- ImageBuffer,\r
- ImageBufferSize,\r
+ Status = FmpDeviceSetImageWithStatus (\r
+ (((UINT8 *) Image) + AllHeaderSize),\r
+ ImageSize - AllHeaderSize,\r
VendorCode,\r
FmpDxeProgress,\r
IncomingFwVersion,\r
- AbortReason\r
+ AbortReason,\r
+ &LastAttemptStatus\r
);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() SetImage from FmpDeviceLib failed. Status = %r.\n", mImageIdName, Status));\r
+\r
+ //\r
+ // LastAttemptStatus returned from the device library should fall within the designated error range\r
+ // [LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE, LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE]\r
+ //\r
+ if ((LastAttemptStatus < LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE) ||\r
+ (LastAttemptStatus > LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE)) {\r
+ DEBUG (\r
+ (DEBUG_ERROR,\r
+ "FmpDxe(%s): SetTheImage() - LastAttemptStatus %d from FmpDeviceSetImageWithStatus() is invalid.\n",\r
+ mImageIdName,\r
+ LastAttemptStatus)\r
+ );\r
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+ }\r
+\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
+ if (Private != NULL) {\r
+ DEBUG ((DEBUG_INFO, "FmpDxe(%s): SetTheImage() LastAttemptStatus: %u.\n", mImageIdName, LastAttemptStatus));\r
+ SetLastAttemptStatusInVariable (Private, LastAttemptStatus);\r
+ }\r
\r
if (Progress != NULL) {\r
//\r
// Need repopulate after SetImage is called to\r
// update LastAttemptVersion and LastAttemptStatus.\r
//\r
- Private->DescriptorPopulated = FALSE;\r
+ if (Private != NULL) {\r
+ Private->DescriptorPopulated = FALSE;\r
+ }\r
\r
return Status;\r
}\r
EFI_STATUS Status;\r
FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private;\r
\r
+ if (Context == NULL) {\r
+ ASSERT (Context != NULL);\r
+ return;\r
+ }\r
+\r
Private = (FIRMWARE_MANAGEMENT_PRIVATE_DATA *)Context;\r
\r
if (!Private->FmpDeviceLocked) {\r
//\r
// PcdFmpDeviceImageIdName must be set to a non-empty Unicode string\r
//\r
- DEBUG ((DEBUG_ERROR, "FmpDxe: PcdFmpDeviceImageIdName is an empty string.\n"));\r
+ DEBUG ((DEBUG_ERROR, "FmpDxe(%g): PcdFmpDeviceImageIdName is an empty string.\n", &gEfiCallerIdGuid));\r
ASSERT (FALSE);\r
return EFI_UNSUPPORTED;\r
}\r