]> git.proxmox.com Git - mirror_edk2.git/blobdiff - FmpDevicePkg/FmpDxe/FmpDxe.c
FmdDevicePkg/FmpDxe: Support Fmp Capsule Dependency.
[mirror_edk2.git] / FmpDevicePkg / FmpDxe / FmpDxe.c
index fe465af11ed96437e140cc84e1d766472aa95f2c..aa92331966c0ae9285573f9650882da5ae19faf8 100644 (file)
@@ -4,7 +4,7 @@
   information provided through PCDs and libraries.\r
 \r
   Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>\r
-  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
 \r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
@@ -12,6 +12,7 @@
 \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
@@ -275,6 +276,13 @@ PopulateDescriptor (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  VOID        *Image;\r
+  UINTN       ImageSize;\r
+  BOOLEAN     IsDepexValid;\r
+  UINT32      DepexSize;\r
+\r
+  Image     = NULL;\r
+  ImageSize = 0;\r
 \r
   if (Private->DescriptorPopulated) {\r
     return;\r
@@ -378,7 +386,47 @@ PopulateDescriptor (
   Private->Descriptor.LastAttemptVersion = GetLastAttemptVersionFromVariable (Private);\r
   Private->Descriptor.LastAttemptStatus  = GetLastAttemptStatusFromVariable (Private);\r
 \r
+  //\r
+  // Get the dependency from the FmpDeviceLib and populate it to the descriptor.\r
+  //\r
+  Private->Descriptor.Dependencies = NULL;\r
+\r
+  //\r
+  // Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY\r
+  //\r
+  if (Private->Descriptor.AttributesSupported & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
+    //\r
+    // The parameter "Image" of FmpDeviceGetImage() is extended to contain the dependency.\r
+    // Get the dependency from the Image.\r
+    //\r
+    ImageSize = Private->Descriptor.Size;\r
+    Image = AllocatePool (ImageSize);\r
+    if (Image != NULL) {\r
+      Status = FmpDeviceGetImage (Image, &ImageSize);\r
+      if (Status == EFI_BUFFER_TOO_SMALL) {\r
+        FreePool (Image);\r
+        Image = AllocatePool (ImageSize);\r
+        if (Image != NULL) {\r
+          Status = FmpDeviceGetImage (Image, &ImageSize);\r
+        }\r
+      }\r
+    }\r
+    if (!EFI_ERROR (Status) && Image != NULL) {\r
+      IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP *) Image, ImageSize, &DepexSize);\r
+      if (IsDepexValid == TRUE) {\r
+        Private->Descriptor.Dependencies = AllocatePool (DepexSize);\r
+        if (Private->Descriptor.Dependencies != NULL) {\r
+          CopyMem (Private->Descriptor.Dependencies->Dependencies, Image, DepexSize);\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
   Private->DescriptorPopulated = TRUE;\r
+\r
+  if (Image != NULL) {\r
+    FreePool (Image);\r
+  }\r
 }\r
 \r
 /**\r
@@ -540,12 +588,17 @@ GetTheImage (
   EFI_STATUS                        Status;\r
   FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;\r
   UINTN                             Size;\r
+  UINT8                             *ImageBuffer;\r
+  UINTN                             ImageBufferSize;\r
+  UINT32                            DepexSize;\r
 \r
   if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  Status = EFI_SUCCESS;\r
+  Status          = EFI_SUCCESS;\r
+  ImageBuffer     = NULL;\r
+  DepexSize       = 0;\r
 \r
   //\r
   // Retrieve the private context structure\r
@@ -575,8 +628,45 @@ GetTheImage (
   if (EFI_ERROR (Status)) {\r
     Size = 0;\r
   }\r
-  if (*ImageSize < Size) {\r
-    *ImageSize = Size;\r
+\r
+  //\r
+  // The parameter "Image" of FmpDeviceGetImage() is extended to contain the dependency.\r
+  // Get the Fmp Payload from the Image.\r
+  //\r
+  ImageBufferSize = Size;\r
+  ImageBuffer = AllocatePool (ImageBufferSize);\r
+  if (ImageBuffer == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - AllocatePool fails.\n", mImageIdName));\r
+    Status = EFI_NOT_FOUND;\r
+    goto cleanup;\r
+  }\r
+  Status = FmpDeviceGetImage (ImageBuffer, &ImageBufferSize);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FreePool (ImageBuffer);\r
+    ImageBuffer = AllocatePool (ImageBufferSize);\r
+    if (ImageBuffer == NULL) {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): GetImage() - AllocatePool fails.\n", mImageIdName));\r
+      Status = EFI_NOT_FOUND;\r
+      goto cleanup;\r
+    }\r
+    Status = FmpDeviceGetImage (ImageBuffer, &ImageBufferSize);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    goto cleanup;\r
+  }\r
+\r
+  //\r
+  // Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY\r
+  //\r
+  if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
+    //\r
+    // Validate the dependency to get its size.\r
+    //\r
+    ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP *) ImageBuffer, ImageBufferSize, &DepexSize);\r
+  }\r
+\r
+  if (*ImageSize < ImageBufferSize - DepexSize) {\r
+    *ImageSize = ImageBufferSize - DepexSize;\r
     DEBUG ((DEBUG_VERBOSE, "FmpDxe(%s): GetImage() - ImageSize is to small.\n", mImageIdName));\r
     Status = EFI_BUFFER_TOO_SMALL;\r
     goto cleanup;\r
@@ -588,8 +678,17 @@ GetTheImage (
     goto cleanup;\r
   }\r
 \r
-  Status = FmpDeviceGetImage (Image, ImageSize);\r
+  //\r
+  // Image is after the dependency expression.\r
+  //\r
+  *ImageSize = ImageBufferSize - DepexSize;\r
+  CopyMem (Image, ImageBuffer + DepexSize, *ImageSize);\r
+  Status = EFI_SUCCESS;\r
+\r
 cleanup:\r
+  if (ImageBuffer != NULL) {\r
+    FreePool (ImageBuffer);\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -710,6 +809,10 @@ CheckTheImage (
   UINTN                             PublicKeyDataLength;\r
   UINT8                             *PublicKeyDataXdr;\r
   UINT8                             *PublicKeyDataXdrEnd;\r
+  EFI_FIRMWARE_IMAGE_DEP            *Dependencies;\r
+  UINT32                            DependenciesSize;\r
+  BOOLEAN                           IsDepexValid;\r
+  BOOLEAN                           IsDepexSatisfied;\r
 \r
   Status           = EFI_SUCCESS;\r
   RawSize          = 0;\r
@@ -718,6 +821,8 @@ CheckTheImage (
   Version          = 0;\r
   FmpHeaderSize    = 0;\r
   AllHeaderSize    = 0;\r
+  Dependencies     = NULL;\r
+  DependenciesSize = 0;\r
 \r
   if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
     return EFI_UNSUPPORTED;\r
@@ -842,10 +947,33 @@ CheckTheImage (
   }\r
   Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));\r
-    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
-    Status = EFI_SUCCESS;\r
-    goto cleanup;\r
+    //\r
+    // Check if there is dependency expression\r
+    //\r
+    IsDepexValid = ValidateImageDepex ((EFI_FIRMWARE_IMAGE_DEP*) FmpPayloadHeader, FmpPayloadSize, &DependenciesSize);\r
+    if (IsDepexValid && (DependenciesSize < FmpPayloadSize)) {\r
+      //\r
+      // Fmp payload is after dependency expression\r
+      //\r
+      Dependencies = (EFI_FIRMWARE_IMAGE_DEP*) FmpPayloadHeader;\r
+      FmpPayloadHeader = (UINT8 *) Dependencies + DependenciesSize;\r
+      FmpPayloadSize = FmpPayloadSize - DependenciesSize;\r
+      Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", mImageIdName, Status));\r
+        *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+        Status = EFI_SUCCESS;\r
+        goto cleanup;\r
+      }\r
+    } else {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency is invalid.\n", mImageIdName));\r
+      mDependenciesCheckStatus = DEPENDENCIES_INVALID;\r
+      *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+      Status = EFI_SUCCESS;\r
+      goto cleanup;\r
+    }\r
+  } else {\r
+    DEBUG ((DEBUG_WARN, "FmpDxe(%s): CheckTheImage() - No dependency associated in image.\n", mImageIdName));\r
   }\r
 \r
   //\r
@@ -862,6 +990,22 @@ CheckTheImage (
     goto cleanup;\r
   }\r
 \r
+  //\r
+  // Evaluate dependency expression\r
+  //\r
+  Status = EvaluateImageDependencies (Private->Descriptor.ImageTypeId, Version, Dependencies, DependenciesSize, &IsDepexSatisfied);\r
+  if (!IsDepexSatisfied || EFI_ERROR (Status)) {\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency check failed %r.\n", mImageIdName, Status));\r
+    } else {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - Dependency is not satisfied.\n", mImageIdName));\r
+    }\r
+    mDependenciesCheckStatus = DEPENDENCIES_UNSATISFIED;\r
+    *ImageUpdatable = IMAGE_UPDATABLE_INVALID;\r
+    Status = EFI_SUCCESS;\r
+    goto cleanup;\r
+  }\r
+\r
   //\r
   // Get the FmpHeaderSize so we can determine the real payload size\r
   //\r
@@ -877,7 +1021,7 @@ CheckTheImage (
   // Call FmpDevice Lib Check Image on the\r
   // Raw payload.  So all headers need stripped off\r
   //\r
-  AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );\r
+  AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize);\r
   if (AllHeaderSize == 0) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): CheckTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
     Status = EFI_ABORTED;\r
@@ -967,6 +1111,11 @@ SetTheImage (
   UINT32                            LastAttemptStatus;\r
   UINT32                            Version;\r
   UINT32                            LowestSupportedVersion;\r
+  EFI_FIRMWARE_IMAGE_DEP            *Dependencies;\r
+  UINT32                            DependenciesSize;\r
+  BOOLEAN                           IsDepexValid;\r
+  UINT8                             *ImageBuffer;\r
+  UINTN                             ImageBufferSize;\r
 \r
   Status             = EFI_SUCCESS;\r
   Updateable         = 0;\r
@@ -975,8 +1124,12 @@ SetTheImage (
   FmpHeader          = NULL;\r
   FmpPayloadSize     = 0;\r
   AllHeaderSize      = 0;\r
-  IncomingFwVersion = 0;\r
+  IncomingFwVersion  = 0;\r
   LastAttemptStatus  = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+  Dependencies       = NULL;\r
+  DependenciesSize   = 0;\r
+  ImageBuffer        = NULL;\r
+  ImageBufferSize    = 0;\r
 \r
   if (!FeaturePcdGet (PcdFmpDeviceStorageAccessEnable)) {\r
     return EFI_UNSUPPORTED;\r
@@ -1008,6 +1161,11 @@ SetTheImage (
     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
@@ -1031,6 +1189,21 @@ SetTheImage (
     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
@@ -1045,6 +1218,11 @@ SetTheImage (
       "FmpDxe(%s): SetTheImage() - Check The Image returned that the Image was not valid for update.  Updatable value = 0x%X.\n",\r
       mImageIdName, Updateable)\r
       );\r
+    if (mDependenciesCheckStatus == DEPENDENCIES_UNSATISFIED) {\r
+      LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSATISFIED_DEPENDENCIES;\r
+    } else if (mDependenciesCheckStatus == DEPENDENCIES_INVALID) {\r
+      LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    }\r
     Status = EFI_ABORTED;\r
     goto cleanup;\r
   }\r
@@ -1138,13 +1316,41 @@ SetTheImage (
     goto cleanup;\r
   }\r
 \r
-  AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );\r
+  AllHeaderSize = GetAllHeaderSize ((EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize + DependenciesSize);\r
   if (AllHeaderSize == 0) {\r
     DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - GetAllHeaderSize failed.\n", mImageIdName));\r
     Status = EFI_ABORTED;\r
     goto cleanup;\r
   }\r
 \r
+  //\r
+  // Check the attribute IMAGE_ATTRIBUTE_DEPENDENCY\r
+  //\r
+  if (Private->Descriptor.AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) {\r
+    //\r
+    // To support saving dependency, extend param "Image" of FmpDeviceSetImage() to\r
+    // contain the dependency inside. FmpDeviceSetImage() is responsible for saving\r
+    // the dependency which can be used for future dependency check.\r
+    //\r
+    ImageBufferSize = DependenciesSize + ImageSize - AllHeaderSize;\r
+    ImageBuffer = AllocatePool (ImageBufferSize);\r
+    if (ImageBuffer == NULL) {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - AllocatePool failed.\n", mImageIdName));\r
+      Status = EFI_ABORTED;\r
+      goto cleanup;\r
+    }\r
+    CopyMem (ImageBuffer, Dependencies->Dependencies, DependenciesSize);\r
+    CopyMem (ImageBuffer + DependenciesSize, (UINT8 *)Image + AllHeaderSize, ImageBufferSize - DependenciesSize);\r
+  } else {\r
+    ImageBufferSize = ImageSize - AllHeaderSize;\r
+    ImageBuffer = AllocateCopyPool(ImageBufferSize, (UINT8 *)Image + AllHeaderSize);\r
+    if (ImageBuffer == NULL) {\r
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): SetTheImage() - AllocatePool failed.\n", mImageIdName));\r
+      Status = EFI_ABORTED;\r
+      goto cleanup;\r
+    }\r
+  }\r
+\r
   //\r
   // Indicate that control is handed off to FmpDeviceLib\r
   //\r
@@ -1154,8 +1360,8 @@ SetTheImage (
   //Copy the requested image to the firmware using the FmpDeviceLib\r
   //\r
   Status = FmpDeviceSetImage (\r
-             (((UINT8 *)Image) + AllHeaderSize),\r
-             ImageSize - AllHeaderSize,\r
+             ImageBuffer,\r
+             ImageBufferSize,\r
              VendorCode,\r
              FmpDxeProgress,\r
              IncomingFwVersion,\r
@@ -1192,6 +1398,10 @@ SetTheImage (
   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