X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=FmpDevicePkg%2FFmpDxe%2FFmpDxe.c;h=58841774fee023ece7ce9549d9fe0ccaa780aa68;hb=0f30087b9a2ce4fd21e318c87bee1a129523a194;hp=3794ac5008f95ecc51cb881540e745e62fa3782e;hpb=27e42bf61bb27a61b5b4dd053c6bc219c73c4cc8;p=mirror_edk2.git diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.c b/FmpDevicePkg/FmpDxe/FmpDxe.c index 3794ac5008..58841774fe 100644 --- a/FmpDevicePkg/FmpDxe/FmpDxe.c +++ b/FmpDevicePkg/FmpDxe/FmpDxe.c @@ -4,64 +4,15 @@ information provided through PCDs and libraries. Copyright (c) 2016, Microsoft Corporation. All rights reserved.
- Copyright (c) 2018, Intel Corporation. All rights reserved.
- - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent **/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "FmpDxe.h" #include "VariableSupport.h" -#define VERSION_STRING_NOT_SUPPORTED L"VERSION STRING NOT SUPPORTED" -#define VERSION_STRING_NOT_AVAILABLE L"VERSION STRING NOT AVAILABLE" - -/** - Check to see if any of the keys in PcdFmpDevicePkcs7CertBufferXdr matches - the test key. PcdFmpDeviceTestKeySha256Digest contains the SHA256 hash of - the test key. For each key in PcdFmpDevicePkcs7CertBufferXdr, compute the - SHA256 hash and compare it to PcdFmpDeviceTestKeySha256Digest. If the - SHA256 hash matches or there is then error computing the SHA256 hash, then - set PcdTestKeyUsed to TRUE. Skip this check if PcdTestKeyUsed is already - TRUE or PcdFmpDeviceTestKeySha256Digest is not exactly SHA256_DIGEST_SIZE - bytes. -**/ -VOID -DetectTestKey ( - VOID - ); - /// /// FILE_GUID from FmpDxe.inf. When FmpDxe.inf is used in a platform, the /// FILE_GUID must always be overridden in the section to provide @@ -73,30 +24,80 @@ const EFI_GUID mDefaultModuleFileGuid = { 0x78ef0a56, 0x1cf0, 0x4535, { 0xb5, 0xda, 0xf6, 0xfd, 0x2f, 0x40, 0x5a, 0x11 } }; -EFI_FIRMWARE_IMAGE_DESCRIPTOR mDesc; -BOOLEAN mDescriptorPopulated = FALSE; -BOOLEAN mRuntimeVersionSupported = TRUE; -BOOLEAN mFmpInstalled = FALSE; - /// -/// Function pointer to progress function +/// TRUE if FmpDeviceLib manages a single firmware storage device. /// -EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS mProgressFunc = NULL; -BOOLEAN mProgressSupported = FALSE; +BOOLEAN mFmpSingleInstance = FALSE; -CHAR16 *mImageIdName = NULL; -UINT64 mImageId = 0x1; -CHAR16 *mVersionName = NULL; +/// +/// Firmware Management Protocol instance that is initialized in the entry +/// point from PCD settings. +/// +EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL mFmpProgress; -EFI_EVENT mFmpDeviceLockEvent; // -// Indicates if an attempt has been made to lock a -// FLASH storage device by calling FmpDeviceLock(). -// A FLASH storage device may not support being locked, -// so this variable is set to TRUE even if FmpDeviceLock() -// returns an error. +// Template of the private context structure for the Firmware Management +// Protocol instance // -BOOLEAN mFmpDeviceLocked = FALSE; +const FIRMWARE_MANAGEMENT_PRIVATE_DATA mFirmwareManagementPrivateDataTemplate = { + FIRMWARE_MANAGEMENT_PRIVATE_DATA_SIGNATURE, // Signature + NULL, // Handle + { // Fmp + GetTheImageInfo, + GetTheImage, + SetTheImage, + CheckTheImage, + GetPackageInfo, + SetPackageInfo + }, + FALSE, // DescriptorPopulated + { // Desc + 1, // ImageIndex + // + // ImageTypeId + // + { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, + 1, // ImageId + NULL, // ImageIdName + 0, // Version + NULL, // VersionName + 0, // Size + 0, // AttributesSupported + 0, // AttributesSetting + 0, // Compatibilities + 0, // LowestSupportedImageVersion + 0, // LastAttemptVersion + 0, // LastAttemptStatus + 0 // HardwareInstance + }, + NULL, // ImageIdName + NULL, // VersionName + TRUE, // RuntimeVersionSupported + NULL, // FmpDeviceLockEvent + FALSE, // FmpDeviceLocked + NULL, // FmpDeviceContext + NULL, // VersionVariableName + NULL, // LsvVariableName + NULL, // LastAttemptStatusVariableName + NULL, // LastAttemptVersionVariableName + NULL, // FmpStateVariableName + TRUE // DependenciesSatisfied +}; + +/// +/// GUID that is used to create event used to lock the firmware storage device. +/// +EFI_GUID *mLockGuid = NULL; + +/// +/// Progress() function pointer passed into SetTheImage() +/// +EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS mProgressFunc = NULL; + +/// +/// Null-terminated Unicode string retrieved from PcdFmpDeviceImageIdName. +/// +CHAR16 *mImageIdName = NULL; /** Callback function to report the process of the firmware updating. @@ -128,10 +129,6 @@ FmpDxeProgress ( Status = EFI_UNSUPPORTED; - if (!mProgressSupported) { - return Status; - } - if (mProgressFunc == NULL) { return Status; } @@ -142,7 +139,6 @@ FmpDxeProgress ( Status = mProgressFunc (((Completion * 92) / 100) + 6); if (Status == EFI_UNSUPPORTED) { - mProgressSupported = FALSE; mProgressFunc = NULL; } @@ -152,9 +148,11 @@ FmpDxeProgress ( /** Returns a pointer to the ImageTypeId GUID value. An attempt is made to get the GUID value from the FmpDeviceLib. If the FmpDeviceLib does not provide - a GUID value, then gEfiCallerIdGuid is returned. + a GUID value, then PcdFmpDeviceImageTypeIdGuid is used. If the size of + PcdFmpDeviceImageTypeIdGuid is not the size of EFI_GUID, then gEfiCallerIdGuid + is returned. - @return The ImageTypeId GUID + @retval The ImageTypeId GUID **/ EFI_GUID * @@ -164,18 +162,26 @@ GetImageTypeIdGuid ( { EFI_STATUS Status; EFI_GUID *FmpDeviceLibGuid; + UINTN ImageTypeIdGuidSize; FmpDeviceLibGuid = NULL; Status = FmpDeviceGetImageTypeIdGuidPtr (&FmpDeviceLibGuid); if (EFI_ERROR (Status)) { if (Status != EFI_UNSUPPORTED) { - DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid error %r\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid error %r\n", mImageIdName, Status)); } - return &gEfiCallerIdGuid; + } else if (FmpDeviceLibGuid == NULL) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid GUID\n", mImageIdName)); + Status = EFI_NOT_FOUND; } - if (FmpDeviceLibGuid == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid GUID\n")); - return &gEfiCallerIdGuid; + if (EFI_ERROR (Status)) { + ImageTypeIdGuidSize = PcdGetSize (PcdFmpDeviceImageTypeIdGuid); + if (ImageTypeIdGuidSize == sizeof (EFI_GUID)) { + FmpDeviceLibGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceImageTypeIdGuid); + } else { + DEBUG ((DEBUG_INFO, "FmpDxe(%s): Fall back to ImageTypeIdGuid of gEfiCallerIdGuid\n", mImageIdName)); + FmpDeviceLibGuid = &gEfiCallerIdGuid; + } } return FmpDeviceLibGuid; } @@ -183,7 +189,7 @@ GetImageTypeIdGuid ( /** Returns a pointer to the Null-terminated Unicode ImageIdName string. - @return Null-terminated Unicode ImageIdName string. + @retval Null-terminated Unicode ImageIdName string. **/ CHAR16 * @@ -200,12 +206,15 @@ GetImageTypeNameString ( 2. Check if we have a variable for lowest supported version (this will be updated with each capsule applied) 3. Check Fixed at build PCD - Take the largest value + @param[in] Private Pointer to the private context structure for the + Firmware Management Protocol instance. + + @retval The largest value **/ UINT32 GetLowestSupportedVersion ( - VOID + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private ) { EFI_STATUS Status; @@ -242,7 +251,7 @@ GetLowestSupportedVersion ( // // Check the lowest supported version UEFI variable for this device // - VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable(); + VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable (Private); if (VariableLowestSupportedVersion > ReturnLsv) { ReturnLsv = VariableLowestSupportedVersion; } @@ -254,101 +263,136 @@ GetLowestSupportedVersion ( } /** - Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the module global - variable mDesc. + Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the private + context structure. + + @param[in] Private Pointer to the private context structure for the + Firmware Management Protocol instance. **/ VOID PopulateDescriptor ( - VOID + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private ) { EFI_STATUS Status; + UINT32 DependenciesSize; - mDesc.ImageIndex = 1; - CopyGuid (&mDesc.ImageTypeId, GetImageTypeIdGuid()); - mDesc.ImageId = mImageId; - mDesc.ImageIdName = GetImageTypeNameString(); + if (Private->DescriptorPopulated) { + return; + } + + Private->Descriptor.ImageIndex = 1; + CopyGuid (&Private->Descriptor.ImageTypeId, GetImageTypeIdGuid()); + Private->Descriptor.ImageId = Private->Descriptor.ImageIndex; + Private->Descriptor.ImageIdName = GetImageTypeNameString(); + + // + // Get the hardware instance from FmpDeviceLib + // + Status = FmpDeviceGetHardwareInstance (&Private->Descriptor.HardwareInstance); + if (Status == EFI_UNSUPPORTED) { + Private->Descriptor.HardwareInstance = 0; + } + + // + // Generate UEFI Variable names used to store status information for this + // FMP instance. + // + GenerateFmpVariableNames (Private); // // Get the version. Some devices don't support getting the firmware version // at runtime. If FmpDeviceLib does not support returning a version, then // it is stored in a UEFI variable. // - Status = FmpDeviceGetVersion (&mDesc.Version); + Status = FmpDeviceGetVersion (&Private->Descriptor.Version); if (Status == EFI_UNSUPPORTED) { - mRuntimeVersionSupported = FALSE; - mDesc.Version = GetVersionFromVariable(); + Private->RuntimeVersionSupported = FALSE; + Private->Descriptor.Version = GetVersionFromVariable (Private); } else if (EFI_ERROR (Status)) { // // Unexpected error. Use default version. // - DEBUG ((DEBUG_ERROR, "FmpDxe: GetVersion() from FmpDeviceLib (%s) returned %r\n", GetImageTypeNameString(), Status)); - mDesc.Version = DEFAULT_VERSION; + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetVersion() from FmpDeviceLib (%s) returned %r\n", mImageIdName, GetImageTypeNameString(), Status)); + Private->Descriptor.Version = DEFAULT_VERSION; } // // Free the current version name. Shouldn't really happen but this populate // function could be called multiple times (to refresh). // - if (mVersionName != NULL) { - FreePool (mVersionName); - mVersionName = NULL; + if (Private->Descriptor.VersionName != NULL) { + FreePool (Private->Descriptor.VersionName); + Private->Descriptor.VersionName = NULL; } // // Attempt to get the version string from the FmpDeviceLib // - Status = FmpDeviceGetVersionString (&mVersionName); + Status = FmpDeviceGetVersionString (&Private->Descriptor.VersionName); if (Status == EFI_UNSUPPORTED) { - DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() unsupported in FmpDeviceLib.\n")); - mVersionName = AllocateCopyPool ( - sizeof (VERSION_STRING_NOT_SUPPORTED), - VERSION_STRING_NOT_SUPPORTED - ); + DEBUG ((DEBUG_INFO, "FmpDxe(%s): GetVersionString() unsupported in FmpDeviceLib.\n", mImageIdName)); + Private->Descriptor.VersionName = AllocateCopyPool ( + sizeof (VERSION_STRING_NOT_SUPPORTED), + VERSION_STRING_NOT_SUPPORTED + ); } else if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() not available in FmpDeviceLib.\n")); - mVersionName = AllocateCopyPool ( - sizeof (VERSION_STRING_NOT_AVAILABLE), - VERSION_STRING_NOT_AVAILABLE - ); + DEBUG ((DEBUG_INFO, "FmpDxe(%s): GetVersionString() not available in FmpDeviceLib.\n", mImageIdName)); + Private->Descriptor.VersionName = AllocateCopyPool ( + sizeof (VERSION_STRING_NOT_AVAILABLE), + VERSION_STRING_NOT_AVAILABLE + ); } - mDesc.VersionName = mVersionName; - - mDesc.LowestSupportedImageVersion = GetLowestSupportedVersion(); + Private->Descriptor.LowestSupportedImageVersion = GetLowestSupportedVersion (Private); // // Get attributes from the FmpDeviceLib // - FmpDeviceGetAttributes (&mDesc.AttributesSupported, &mDesc.AttributesSetting); + FmpDeviceGetAttributes ( + &Private->Descriptor.AttributesSupported, + &Private->Descriptor.AttributesSetting + ); // // Force set the updatable bits in the attributes; // - mDesc.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; - mDesc.AttributesSetting |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; + Private->Descriptor.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; + Private->Descriptor.AttributesSetting |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; // // Force set the authentication bits in the attributes; // - mDesc.AttributesSupported |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); - mDesc.AttributesSetting |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Private->Descriptor.AttributesSupported |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Private->Descriptor.AttributesSetting |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); - mDesc.Compatibilities = 0; + Private->Descriptor.Compatibilities = 0; // // Get the size of the firmware image from the FmpDeviceLib // - Status = FmpDeviceGetSize (&mDesc.Size); + Status = FmpDeviceGetSize (&Private->Descriptor.Size); if (EFI_ERROR (Status)) { - mDesc.Size = 0; + Private->Descriptor.Size = 0; } - mDesc.LastAttemptVersion = GetLastAttemptVersionFromVariable (); - mDesc.LastAttemptStatus = GetLastAttemptStatusFromVariable (); + Private->Descriptor.LastAttemptVersion = GetLastAttemptVersionFromVariable (Private); + Private->Descriptor.LastAttemptStatus = GetLastAttemptStatusFromVariable (Private); - mDescriptorPopulated = TRUE; + // + // Get the dependency from the FmpDependencyDeviceLib. + // + Private->Descriptor.Dependencies = NULL; + + // + // Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY + // + if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) { + Private->Descriptor.Dependencies = GetFmpDependency (&DependenciesSize); + } + + Private->DescriptorPopulated = TRUE; } /** @@ -402,15 +446,22 @@ GetTheImageInfo ( OUT CHAR16 **PackageVersionName ) { - EFI_STATUS Status; + EFI_STATUS Status; + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private; Status = EFI_SUCCESS; + // + // Retrieve the private context structure + // + Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This); + FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext); + // // Check for valid pointer // if (ImageInfoSize == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - ImageInfoSize is NULL.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImageInfo() - ImageInfoSize is NULL.\n", mImageIdName)); Status = EFI_INVALID_PARAMETER; goto cleanup; } @@ -421,7 +472,7 @@ GetTheImageInfo ( // if (*ImageInfoSize < (sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR))) { *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR); - DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImageInfo() - ImageInfoSize is to small.\n")); + DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImageInfo() - ImageInfoSize is to small.\n", mImageIdName)); Status = EFI_BUFFER_TOO_SMALL; goto cleanup; } @@ -431,7 +482,7 @@ GetTheImageInfo ( // if ( (ImageInfo == NULL) || (DescriptorVersion == NULL) || (DescriptorCount == NULL) || (DescriptorSize == NULL) || (PackageVersion == NULL)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - Pointer Parameter is NULL.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImageInfo() - Pointer Parameter is NULL.\n", mImageIdName)); Status = EFI_INVALID_PARAMETER; goto cleanup; } @@ -441,15 +492,15 @@ GetTheImageInfo ( // *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR); - - if (!mDescriptorPopulated) { - PopulateDescriptor(); - } + // + // Make sure the descriptor has already been loaded or refreshed + // + PopulateDescriptor (Private); // // Copy the image descriptor // - CopyMem (ImageInfo, &mDesc, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR)); + CopyMem (ImageInfo, &Private->Descriptor, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR)); *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; *DescriptorCount = 1; @@ -500,22 +551,33 @@ GetTheImage ( IN OUT UINTN *ImageSize ) { - EFI_STATUS Status; - UINTN Size; + EFI_STATUS Status; + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private; + UINTN Size; + + if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) { + return EFI_UNSUPPORTED; + } Status = EFI_SUCCESS; + // + // Retrieve the private context structure + // + Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This); + FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext); + // // Check to make sure index is 1 (only 1 image for this device) // if (ImageIndex != 1) { - DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Index Invalid.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - Image Index Invalid.\n", mImageIdName)); Status = EFI_INVALID_PARAMETER; goto cleanup; } if (ImageSize == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - ImageSize Pointer Parameter is NULL.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - ImageSize Pointer Parameter is NULL.\n", mImageIdName)); Status = EFI_INVALID_PARAMETER; goto cleanup; } @@ -529,13 +591,13 @@ GetTheImage ( } if (*ImageSize < Size) { *ImageSize = Size; - DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImage() - ImageSize is to small.\n")); + DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImage() - ImageSize is to small.\n", mImageIdName)); Status = EFI_BUFFER_TOO_SMALL; goto cleanup; } if (Image == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Pointer Parameter is NULL.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - Image Pointer Parameter is NULL.\n", mImageIdName)); Status = EFI_INVALID_PARAMETER; goto cleanup; } @@ -550,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. @@ -562,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); } /** @@ -649,18 +713,21 @@ CheckTheImage ( OUT UINT32 *ImageUpdatable ) { - EFI_STATUS Status; - UINTN RawSize; - VOID *FmpPayloadHeader; - UINTN FmpPayloadSize; - UINT32 Version; - UINT32 FmpHeaderSize; - UINTN AllHeaderSize; - UINT32 Index; - VOID *PublicKeyData; - UINTN PublicKeyDataLength; - UINT8 *PublicKeyDataXdr; - UINT8 *PublicKeyDataXdrEnd; + EFI_STATUS Status; + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private; + UINTN RawSize; + VOID *FmpPayloadHeader; + UINTN FmpPayloadSize; + UINT32 Version; + UINT32 FmpHeaderSize; + UINTN AllHeaderSize; + UINT32 Index; + VOID *PublicKeyData; + UINTN PublicKeyDataLength; + UINT8 *PublicKeyDataXdr; + UINT8 *PublicKeyDataXdrEnd; + EFI_FIRMWARE_IMAGE_DEP *Dependencies; + UINT32 DependenciesSize; Status = EFI_SUCCESS; RawSize = 0; @@ -669,16 +736,26 @@ CheckTheImage ( Version = 0; FmpHeaderSize = 0; AllHeaderSize = 0; + Dependencies = NULL; + DependenciesSize = 0; + + if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) { + return EFI_UNSUPPORTED; + } // - // make sure the descriptor has already been loaded + // Retrieve the private context structure // - if (!mDescriptorPopulated) { - PopulateDescriptor(); - } + Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This); + FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext); + + // + // Make sure the descriptor has already been loaded or refreshed + // + PopulateDescriptor (Private); if (ImageUpdatable == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n", mImageIdName)); Status = EFI_INVALID_PARAMETER; goto cleanup; } @@ -688,8 +765,13 @@ 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: CheckImage() - Image Pointer Parameter is NULL.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Pointer Parameter is NULL.\n", mImageIdName)); // // not sure if this is needed // @@ -701,7 +783,7 @@ CheckTheImage ( PublicKeyDataXdrEnd = PublicKeyDataXdr + PcdGetSize (PcdFmpDevicePkcs7CertBufferXdr); if (PublicKeyDataXdr == NULL || (PublicKeyDataXdr == PublicKeyDataXdrEnd)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: Invalid certificate, skipping it.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Invalid certificate, skipping it.\n", mImageIdName)); Status = EFI_ABORTED; } else { // @@ -711,7 +793,8 @@ CheckTheImage ( Index++; DEBUG ( (DEBUG_INFO, - "FmpDxe: Certificate #%d [%p..%p].\n", + "FmpDxe(%s): Certificate #%d [%p..%p].\n", + mImageIdName, Index, PublicKeyDataXdr, PublicKeyDataXdrEnd @@ -722,7 +805,7 @@ CheckTheImage ( // // Key data extends beyond end of PCD // - DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate size extends beyond end of PCD, skipping it.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate size extends beyond end of PCD, skipping it.\n", mImageIdName)); Status = EFI_ABORTED; break; } @@ -738,7 +821,7 @@ CheckTheImage ( // // Key data extends beyond end of PCD // - DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate extends beyond end of PCD, skipping it.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Certificate extends beyond end of PCD, skipping it.\n", mImageIdName)); Status = EFI_ABORTED; break; } @@ -758,7 +841,7 @@ CheckTheImage ( } if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - Authentication Failed %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Authentication Failed %r.\n", mImageIdName, Status)); goto cleanup; } @@ -766,25 +849,29 @@ CheckTheImage ( // Check to make sure index is 1 // if (ImageIndex != 1) { - DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - Image Index Invalid.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckImage() - Image Index Invalid.\n", mImageIdName)); *ImageUpdatable = IMAGE_UPDATABLE_INVALID_TYPE; Status = EFI_SUCCESS; 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: CheckTheImage() - GetFmpHeader failed.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpHeader failed.\n", mImageIdName)); Status = EFI_ABORTED; goto cleanup; } Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status)); *ImageUpdatable = IMAGE_UPDATABLE_INVALID; Status = EFI_SUCCESS; goto cleanup; @@ -793,17 +880,28 @@ CheckTheImage ( // // Check the lowest supported version // - if (Version < mDesc.LowestSupportedImageVersion) { + if (Version < Private->Descriptor.LowestSupportedImageVersion) { DEBUG ( (DEBUG_ERROR, - "FmpDxe: CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n", - Version, mDesc.LowestSupportedImageVersion) + "FmpDxe(%s): CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n", + mImageIdName, Version, Private->Descriptor.LowestSupportedImageVersion) ); *ImageUpdatable = IMAGE_UPDATABLE_INVALID_OLD; Status = EFI_SUCCESS; goto cleanup; } + // + // Evaluate dependency expression + // + 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; + } + // // Get the FmpHeaderSize so we can determine the real payload size // @@ -819,9 +917,9 @@ CheckTheImage ( // Call FmpDevice Lib Check Image on the // Raw payload. So all headers need stripped off // - AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize ); + AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize); if (AllHeaderSize == 0) { - DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetAllHeaderSize failed.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetAllHeaderSize failed.\n", mImageIdName)); Status = EFI_ABORTED; goto cleanup; } @@ -832,7 +930,7 @@ CheckTheImage ( // Status = FmpDeviceCheckImage ((((UINT8 *)Image) + AllHeaderSize), RawSize, ImageUpdatable); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - FmpDeviceLib CheckImage failed. Status = %r\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - FmpDeviceLib CheckImage failed. Status = %r\n", mImageIdName, Status)); } cleanup: @@ -897,17 +995,20 @@ SetTheImage ( OUT CHAR16 **AbortReason ) { - EFI_STATUS Status; - UINT32 Updateable; - BOOLEAN BooleanValue; - UINT32 FmpHeaderSize; - VOID *FmpHeader; - UINTN FmpPayloadSize; - UINT32 AllHeaderSize; - UINT32 IncommingFwVersion; - UINT32 LastAttemptStatus; - UINT32 Version; - UINT32 LowestSupportedVersion; + EFI_STATUS Status; + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private; + UINT32 Updateable; + BOOLEAN BooleanValue; + UINT32 FmpHeaderSize; + VOID *FmpHeader; + UINTN FmpPayloadSize; + UINT32 AllHeaderSize; + UINT32 IncomingFwVersion; + UINT32 LastAttemptStatus; + UINT32 Version; + UINT32 LowestSupportedVersion; + EFI_FIRMWARE_IMAGE_DEP *Dependencies; + UINT32 DependenciesSize; Status = EFI_SUCCESS; Updateable = 0; @@ -916,18 +1017,37 @@ SetTheImage ( FmpHeader = NULL; FmpPayloadSize = 0; AllHeaderSize = 0; - IncommingFwVersion = 0; + IncomingFwVersion = 0; LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + Dependencies = NULL; + DependenciesSize = 0; + + if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) { + return EFI_UNSUPPORTED; + } + + // + // Retrieve the private context structure + // + Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This); + FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext); + // + // Make sure the descriptor has already been loaded or refreshed + // + PopulateDescriptor (Private); - SetLastAttemptVersionInVariable (IncommingFwVersion); //set to 0 to clear any previous results. + // + // Set to 0 to clear any previous results. + // + SetLastAttemptVersionInVariable (Private, IncomingFwVersion); // // if we have locked the device, then skip the set operation. // it should be blocked by hardware too but we can catch here even faster // - if (mFmpDeviceLocked) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Device is already locked. Can't update.\n")); + if (Private->FmpDeviceLocked) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Device is already locked. Can't update.\n", mImageIdName)); Status = EFI_UNSUPPORTED; goto cleanup; } @@ -937,57 +1057,64 @@ SetTheImage ( // Status = CheckTheImage (This, ImageIndex, Image, ImageSize, &Updateable); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Check The Image failed with %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Check The Image failed with %r.\n", mImageIdName, Status)); if (Status == EFI_SECURITY_VIOLATION) { LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR; } 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: SetTheImage() - GetFmpHeader failed.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpHeader failed.\n", mImageIdName)); Status = EFI_ABORTED; goto cleanup; } - Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncommingFwVersion); + Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncomingFwVersion); if (!EFI_ERROR (Status)) { // // Set to actual value // - SetLastAttemptVersionInVariable (IncommingFwVersion); + SetLastAttemptVersionInVariable (Private, IncomingFwVersion); } if (Updateable != IMAGE_UPDATABLE_VALID) { DEBUG ( (DEBUG_ERROR, - "FmpDxed: SetTheImage() - Check The Image returned that the Image was not valid for update. Updatable value = 0x%X.\n", - Updateable) + "FmpDxe(%s): SetTheImage() - Check The Image returned that the Image was not valid for update. Updatable value = 0x%X.\n", + mImageIdName, Updateable) ); + if (Private->DependenciesSatisfied == FALSE) { + LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSATISFIED_DEPENDENCIES; + } Status = EFI_ABORTED; goto cleanup; } if (Progress == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Invalid progress callback\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Invalid progress callback\n", mImageIdName)); Status = EFI_INVALID_PARAMETER; goto cleanup; } mProgressFunc = Progress; - mProgressSupported = TRUE; // // Checking the image is at least 1% // Status = Progress (1); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Progress Callback failed with Status %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - Progress Callback failed with Status %r.\n", mImageIdName, Status)); } // @@ -995,14 +1122,14 @@ SetTheImage ( // Status = CheckSystemPower (&BooleanValue); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemPower - API call failed %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemPower - API call failed %r.\n", mImageIdName, Status)); goto cleanup; } if (!BooleanValue) { Status = EFI_ABORTED; DEBUG ( (DEBUG_ERROR, - "FmpDxe: SetTheImage() - CheckSystemPower - returned False. Update not allowed due to System Power.\n") + "FmpDxe(%s): SetTheImage() - CheckSystemPower - returned False. Update not allowed due to System Power.\n", mImageIdName) ); LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_BATT; goto cleanup; @@ -1015,14 +1142,14 @@ SetTheImage ( // Status = CheckSystemThermal (&BooleanValue); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemThermal - API call failed %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemThermal - API call failed %r.\n", mImageIdName, Status)); goto cleanup; } if (!BooleanValue) { Status = EFI_ABORTED; DEBUG ( (DEBUG_ERROR, - "FmpDxe: SetTheImage() - CheckSystemThermal - returned False. Update not allowed due to System Thermal.\n") + "FmpDxe(%s): SetTheImage() - CheckSystemThermal - returned False. Update not allowed due to System Thermal.\n", mImageIdName) ); goto cleanup; } @@ -1034,14 +1161,14 @@ SetTheImage ( // Status = CheckSystemEnvironment (&BooleanValue); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemEnvironment - API call failed %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - API call failed %r.\n", mImageIdName, Status)); goto cleanup; } if (!BooleanValue) { Status = EFI_ABORTED; DEBUG ( (DEBUG_ERROR, - "FmpDxe: SetTheImage() - CheckSystemEnvironment - returned False. Update not allowed due to System Environment.\n") + "FmpDxe(%s): SetTheImage() - CheckSystemEnvironment - returned False. Update not allowed due to System Environment.\n", mImageIdName) ); goto cleanup; } @@ -1052,20 +1179,20 @@ SetTheImage ( // Save LastAttemptStatus as error so that if SetImage never returns the error // state is recorded. // - SetLastAttemptStatusInVariable (LastAttemptStatus); + SetLastAttemptStatusInVariable (Private, LastAttemptStatus); // // Strip off all the headers so the device can process its firmware // Status = GetFmpPayloadHeaderSize (FmpHeader, FmpPayloadSize, &FmpHeaderSize); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetFmpPayloadHeaderSize failed %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetFmpPayloadHeaderSize failed %r.\n", mImageIdName, Status)); goto cleanup; } - AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize ); + AllHeaderSize = GetAllHeaderSize ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize); if (AllHeaderSize == 0) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetAllHeaderSize failed.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetAllHeaderSize failed.\n", mImageIdName)); Status = EFI_ABORTED; goto cleanup; } @@ -1083,14 +1210,24 @@ SetTheImage ( ImageSize - AllHeaderSize, VendorCode, FmpDxeProgress, - IncommingFwVersion, + IncomingFwVersion, AbortReason ); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() SetImage from FmpDeviceLib failed. Status = %r.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() SetImage from FmpDeviceLib failed. Status = %r.\n", mImageIdName, Status)); 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 @@ -1101,27 +1238,24 @@ SetTheImage ( // // Update the version stored in variable // - if (!mRuntimeVersionSupported) { + if (!Private->RuntimeVersionSupported) { Version = DEFAULT_VERSION; GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &Version); - SetVersionInVariable (Version); + SetVersionInVariable (Private, Version); } // // Update lowest supported variable // - { - LowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION; - GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, &LowestSupportedVersion); - SetLowestSupportedVersionInVariable (LowestSupportedVersion); - } + LowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION; + GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, &LowestSupportedVersion); + SetLowestSupportedVersionInVariable (Private, LowestSupportedVersion); LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; cleanup: mProgressFunc = NULL; - mProgressSupported = FALSE; - SetLastAttemptStatusInVariable (LastAttemptStatus); + SetLastAttemptStatusInVariable (Private, LastAttemptStatus); if (Progress != NULL) { // @@ -1134,7 +1268,7 @@ cleanup: // Need repopulate after SetImage is called to // update LastAttemptVersion and LastAttemptStatus. // - mDescriptorPopulated = FALSE; + Private->DescriptorPopulated = FALSE; return Status; } @@ -1245,35 +1379,25 @@ FmpDxeLockEventNotify ( IN VOID *Context ) { - EFI_STATUS Status; + EFI_STATUS Status; + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private; - if (!mFmpDeviceLocked) { - if (IsLockFmpDeviceAtLockEventGuidRequired ()) { - // - // Lock all UEFI Variables used by this module. - // - Status = LockAllFmpVariables (); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variables. Status = %r.\n")); - } else { - DEBUG ((DEBUG_INFO, "FmpDxe: All variables locked\n")); - } + Private = (FIRMWARE_MANAGEMENT_PRIVATE_DATA *)Context; - // - // Lock the firmware device - // - Status = FmpDeviceLock(); - if (EFI_ERROR (Status)) { - if (Status != EFI_UNSUPPORTED) { - DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLock() returned error. Status = %r\n", Status)); - } else { - DEBUG ((DEBUG_WARN, "FmpDxe: FmpDeviceLock() returned error. Status = %r\n", Status)); - } + if (!Private->FmpDeviceLocked) { + // + // Lock the firmware device + // + FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext); + Status = FmpDeviceLock(); + if (EFI_ERROR (Status)) { + if (Status != EFI_UNSUPPORTED) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLock() returned error. Status = %r\n", mImageIdName, Status)); + } else { + DEBUG ((DEBUG_WARN, "FmpDxe(%s): FmpDeviceLock() returned error. Status = %r\n", mImageIdName, Status)); } - mFmpDeviceLocked = TRUE; - } else { - DEBUG ((DEBUG_VERBOSE, "FmpDxe: Not calling FmpDeviceLock() because mfg mode\n")); } + Private->FmpDeviceLocked = TRUE; } } @@ -1293,85 +1417,233 @@ InstallFmpInstance ( IN EFI_HANDLE Handle ) { - EFI_STATUS Status; - EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; - EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *FmpProgress; - - Status = EFI_SUCCESS; - Fmp = NULL; - FmpProgress = NULL; + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private; // // Only allow a single FMP Protocol instance to be installed // - if (mFmpInstalled) { + Status = gBS->OpenProtocol ( + Handle, + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { return EFI_ALREADY_STARTED; } // // Allocate FMP Protocol instance // - Fmp = AllocateZeroPool (sizeof (EFI_FIRMWARE_MANAGEMENT_PROTOCOL)); - if (Fmp == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Protocol instance.\n")); + Private = AllocateCopyPool ( + sizeof (mFirmwareManagementPrivateDataTemplate), + &mFirmwareManagementPrivateDataTemplate + ); + if (Private == NULL) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to allocate memory for private structure.\n", mImageIdName)); Status = EFI_OUT_OF_RESOURCES; goto cleanup; } // - // Allocate FMP Progress Protocol instance + // Initialize private context data structure // - FmpProgress = AllocateZeroPool (sizeof (EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL)); - if (FmpProgress == NULL) { - DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Progress Protocol instance.\n")); - Status = EFI_OUT_OF_RESOURCES; - FreePool (Fmp); + Private->Handle = Handle; + Private->FmpDeviceContext = NULL; + Status = FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext); + if (Status == EFI_UNSUPPORTED) { + Private->FmpDeviceContext = NULL; + } else if (EFI_ERROR (Status)) { goto cleanup; } // - // Set up FMP Protocol function pointers + // Make sure the descriptor has already been loaded or refreshed // - Fmp->GetImageInfo = GetTheImageInfo; - Fmp->GetImage = GetTheImage; - Fmp->SetImage = SetTheImage; - Fmp->CheckImage = CheckTheImage; - Fmp->GetPackageInfo = GetPackageInfo; - Fmp->SetPackageInfo = SetPackageInfo; + PopulateDescriptor (Private); - // - // Fill in FMP Progress Protocol fields for Version 1 - // - FmpProgress->Version = 1; - FmpProgress->ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor); - FmpProgress->WatchdogSeconds = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds); + if (IsLockFmpDeviceAtLockEventGuidRequired ()) { + // + // Register all UEFI Variables used by this module to be locked. + // + Status = LockAllFmpVariables (Private); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to register variables to lock. Status = %r.\n", mImageIdName, Status)); + } else { + DEBUG ((DEBUG_INFO, "FmpDxe(%s): All variables registered to lock\n", mImageIdName)); + } + + // + // Create and register notify function to lock the FMP device. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + FmpDxeLockEventNotify, + Private, + mLockGuid, + &Private->FmpDeviceLockEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to register notification. Status = %r\n", mImageIdName, Status)); + } + ASSERT_EFI_ERROR (Status); + } else { + DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): Not registering notification to call FmpDeviceLock() because mfg mode\n", mImageIdName)); + } // // Install FMP Protocol and FMP Progress Protocol // Status = gBS->InstallMultipleProtocolInterfaces ( - &Handle, - &gEfiFirmwareManagementProtocolGuid, - Fmp, - &gEdkiiFirmwareManagementProgressProtocolGuid, - FmpProgress, + &Private->Handle, + &gEfiFirmwareManagementProtocolGuid, &Private->Fmp, + &gEdkiiFirmwareManagementProgressProtocolGuid, &mFmpProgress, NULL ); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: FMP Protocol install error. Status = %r.\n", Status)); - FreePool (Fmp); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Protocol install error. Status = %r.\n", mImageIdName, Status)); goto cleanup; } - DEBUG ((DEBUG_INFO, "FmpDxe: FMP Protocol Installed!\n")); - mFmpInstalled = TRUE; - cleanup: + if (EFI_ERROR (Status)) { + if (Private != NULL) { + if (Private->FmpDeviceLockEvent != NULL) { + gBS->CloseEvent (Private->FmpDeviceLockEvent); + } + if (Private->Descriptor.VersionName != NULL) { + FreePool (Private->Descriptor.VersionName); + } + if (Private->FmpDeviceContext != NULL) { + FmpDeviceSetContext (NULL, &Private->FmpDeviceContext); + } + if (Private->VersionVariableName != NULL) { + FreePool (Private->VersionVariableName); + } + if (Private->LsvVariableName != NULL) { + FreePool (Private->LsvVariableName); + } + if (Private->LastAttemptStatusVariableName != NULL) { + FreePool (Private->LastAttemptStatusVariableName); + } + if (Private->LastAttemptVersionVariableName != NULL) { + FreePool (Private->LastAttemptVersionVariableName); + } + if (Private->FmpStateVariableName != NULL) { + FreePool (Private->FmpStateVariableName); + } + FreePool (Private); + } + } + return Status; } +/** + Function to uninstall FMP instance. + + @param[in] Handle The device handle to install a FMP instance on. + + @retval EFI_SUCCESS FMP Installed + @retval EFI_INVALID_PARAMETER Handle was invalid + @retval other Error installing FMP + +**/ +EFI_STATUS +EFIAPI +UninstallFmpInstance ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Protocol open error. Status = %r.\n", mImageIdName, Status)); + return Status; + } + + Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (Fmp); + FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext); + + if (Private->FmpDeviceLockEvent != NULL) { + gBS->CloseEvent (Private->FmpDeviceLockEvent); + } + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Private->Handle, + &gEfiFirmwareManagementProtocolGuid, &Private->Fmp, + &gEdkiiFirmwareManagementProgressProtocolGuid, &mFmpProgress, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Protocol uninstall error. Status = %r.\n", mImageIdName, Status)); + return Status; + } + + if (Private->Descriptor.VersionName != NULL) { + FreePool (Private->Descriptor.VersionName); + } + if (Private->FmpDeviceContext != NULL) { + FmpDeviceSetContext (NULL, &Private->FmpDeviceContext); + } + if (Private->VersionVariableName != NULL) { + FreePool (Private->VersionVariableName); + } + if (Private->LsvVariableName != NULL) { + FreePool (Private->LsvVariableName); + } + if (Private->LastAttemptStatusVariableName != NULL) { + FreePool (Private->LastAttemptStatusVariableName); + } + if (Private->LastAttemptVersionVariableName != NULL) { + FreePool (Private->LastAttemptVersionVariableName); + } + if (Private->FmpStateVariableName != NULL) { + FreePool (Private->FmpStateVariableName); + } + FreePool (Private); + + return EFI_SUCCESS; +} + +/** + Unloads the application and its installed protocol. + + @param ImageHandle Handle that identifies the image to be unloaded. + @param SystemTable The system table. + + @retval EFI_SUCCESS The image has been unloaded. + +**/ +EFI_STATUS +EFIAPI +FmpDxeLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (mFmpSingleInstance) { + return UninstallFmpInstance (ImageHandle); + } + return EFI_SUCCESS; +} + /** Main entry for this driver/library. @@ -1387,7 +1659,6 @@ FmpDxeEntryPoint ( ) { EFI_STATUS Status; - EFI_GUID *LockGuid; // // Verify that a new FILE_GUID value has been provided in the @@ -1408,8 +1679,9 @@ FmpDxeEntryPoint ( // // PcdFmpDeviceImageIdName must be set to a non-empty Unicode string // - DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib PcdFmpDeviceImageIdName is an empty string.\n")); + DEBUG ((DEBUG_ERROR, "FmpDxe: PcdFmpDeviceImageIdName is an empty string.\n")); ASSERT (FALSE); + return EFI_UNSUPPORTED; } // @@ -1417,6 +1689,23 @@ FmpDxeEntryPoint ( // DetectTestKey (); + // + // Fill in FMP Progress Protocol fields for Version 1 + // + mFmpProgress.Version = 1; + mFmpProgress.ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor); + mFmpProgress.WatchdogSeconds = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds); + + // The lock event GUID is retrieved from PcdFmpDeviceLockEventGuid. + // If PcdFmpDeviceLockEventGuid is not the size of an EFI_GUID, then + // gEfiEndOfDxeEventGroupGuid is used. + // + mLockGuid = &gEfiEndOfDxeEventGroupGuid; + if (PcdGetSize (PcdFmpDeviceLockEventGuid) == sizeof (EFI_GUID)) { + mLockGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceLockEventGuid); + } + DEBUG ((DEBUG_INFO, "FmpDxe(%s): Lock GUID: %g\n", mImageIdName, mLockGuid)); + // // Register with library the install function so if the library uses // UEFI driver model/driver binding protocol it can install FMP on its device handle @@ -1425,41 +1714,28 @@ FmpDxeEntryPoint ( // Status = RegisterFmpInstaller (InstallFmpInstance); if (Status == EFI_UNSUPPORTED) { - DEBUG ((DEBUG_INFO, "FmpDxe: FmpDeviceLib registration returned EFI_UNSUPPORTED. Installing single FMP instance.\n")); - Status = InstallFmpInstance (ImageHandle); + mFmpSingleInstance = TRUE; + DEBUG ((DEBUG_INFO, "FmpDxe(%s): FmpDeviceLib registration returned EFI_UNSUPPORTED. Installing single FMP instance.\n", mImageIdName)); + Status = RegisterFmpUninstaller (UninstallFmpInstance); + if (Status == EFI_UNSUPPORTED) { + Status = InstallFmpInstance (ImageHandle); + } else { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib RegisterFmpInstaller and RegisterFmpUninstaller do not match.\n", mImageIdName)); + Status = EFI_UNSUPPORTED; + } } else if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib registration returned %r. No FMP installed.\n", Status)); + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib registration returned %r. No FMP installed.\n", mImageIdName, Status)); } else { DEBUG (( DEBUG_INFO, - "FmpDxe: FmpDeviceLib registration returned EFI_SUCCESS. Expect FMP to be installed during the BDS/Device connection phase.\n" + "FmpDxe(%s): FmpDeviceLib registration returned EFI_SUCCESS. Expect FMP to be installed during the BDS/Device connection phase.\n", + mImageIdName )); + Status = RegisterFmpUninstaller (UninstallFmpInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FmpDxe(%s): FmpDeviceLib RegisterFmpInstaller and RegisterFmpUninstaller do not match.\n", mImageIdName)); + } } - // - // Register notify function to lock the FMP device. - // The lock event GUID is retrieved from PcdFmpDeviceLockEventGuid. - // If PcdFmpDeviceLockEventGuid is not the size of an EFI_GUID, then - // gEfiEndOfDxeEventGroupGuid is used. - // - LockGuid = &gEfiEndOfDxeEventGroupGuid; - if (PcdGetSize (PcdFmpDeviceLockEventGuid) == sizeof (EFI_GUID)) { - LockGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceLockEventGuid); - } - DEBUG ((DEBUG_INFO, "FmpDxe: Lock GUID: %g\n", LockGuid)); - - Status = gBS->CreateEventEx ( - EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, - FmpDxeLockEventNotify, - NULL, - LockGuid, - &mFmpDeviceLockEvent - ); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to register for ready to boot. Status = %r\n", Status)); - } - ASSERT_EFI_ERROR (Status); - return Status; }