@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
EFI_FIRMWARE_IMAGE_DEP *Dependencies;\r
UINT32 DependenciesSize;\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
+ 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
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
// 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
DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Index Invalid.\n", mImageIdName));\r
*ImageUpdatable = IMAGE_UPDATABLE_INVALID_TYPE;\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 ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &DependenciesSize);\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
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
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
*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
- Private->DependenciesSatisfied = CheckFmpDependency (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize);\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
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
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
// 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);\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
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
\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
//Copy the requested image to the firmware using the FmpDeviceLib\r
//\r
- Status = FmpDeviceSetImage (\r
- (((UINT8 *)Image) + AllHeaderSize),\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
mProgressFunc = NULL;\r
\r
if (Private != NULL) {\r
+ DEBUG ((DEBUG_INFO, "FmpDxe(%s): SetTheImage() LastAttemptStatus: %u.\n", mImageIdName, LastAttemptStatus));\r
SetLastAttemptStatusInVariable (Private, LastAttemptStatus);\r
}\r
\r