The FMP dependency libraries are leveraged during firmware update to check for dependencies required to update the image. This change adds granular Last Attempt Status code support to these services so failures can be more easily observed during the firmware update process via Last Attempt Status codes. Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Guomin Jiang <guomin.jiang@intel.com> Cc: Wei6 Xu <wei6.xu@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn> Reviewed-by: Wei6 Xu <wei6.xu@intel.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
		
			
				
	
	
		
			614 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			614 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Supports Fmp Capsule Dependency Expression.
 | 
						|
 | 
						|
  Copyright (c) Microsoft Corporation.<BR>
 | 
						|
  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
#include <PiDxe.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/FmpDependencyLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Guid/SystemResourceTable.h>
 | 
						|
#include <LastAttemptStatus.h>
 | 
						|
#include <FmpLastAttemptStatus.h>
 | 
						|
 | 
						|
//
 | 
						|
// Define the initial size of the dependency expression evaluation stack
 | 
						|
//
 | 
						|
#define DEPEX_STACK_SIZE_INCREMENT  0x1000
 | 
						|
 | 
						|
//
 | 
						|
// Type of stack element
 | 
						|
//
 | 
						|
typedef enum {
 | 
						|
  BooleanType,
 | 
						|
  VersionType
 | 
						|
} ELEMENT_TYPE;
 | 
						|
 | 
						|
//
 | 
						|
// Value of stack element
 | 
						|
//
 | 
						|
typedef union {
 | 
						|
  BOOLEAN   Boolean;
 | 
						|
  UINT32    Version;
 | 
						|
} ELEMENT_VALUE;
 | 
						|
 | 
						|
//
 | 
						|
// Stack element used to evaluate dependency expressions
 | 
						|
//
 | 
						|
typedef struct {
 | 
						|
  ELEMENT_VALUE Value;
 | 
						|
  ELEMENT_TYPE  Type;
 | 
						|
} DEPEX_ELEMENT;
 | 
						|
 | 
						|
//
 | 
						|
// Global stack used to evaluate dependency expressions
 | 
						|
//
 | 
						|
DEPEX_ELEMENT  *mDepexEvaluationStack        = NULL;
 | 
						|
DEPEX_ELEMENT  *mDepexEvaluationStackEnd     = NULL;
 | 
						|
DEPEX_ELEMENT  *mDepexEvaluationStackPointer = NULL;
 | 
						|
 | 
						|
/**
 | 
						|
  Grow size of the Depex stack
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Stack successfully growed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  There is not enough system memory to grow the stack.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GrowDepexStack (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEPEX_ELEMENT  *NewStack;
 | 
						|
  UINTN          Size;
 | 
						|
 | 
						|
  Size = DEPEX_STACK_SIZE_INCREMENT;
 | 
						|
  if (mDepexEvaluationStack != NULL) {
 | 
						|
    Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);
 | 
						|
  }
 | 
						|
 | 
						|
  NewStack = AllocatePool (Size * sizeof (DEPEX_ELEMENT));
 | 
						|
  if (NewStack == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "GrowDepexStack: Cannot allocate memory for dependency evaluation stack!\n"));
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  if (mDepexEvaluationStack != NULL) {
 | 
						|
    //
 | 
						|
    // Copy to Old Stack to the New Stack
 | 
						|
    //
 | 
						|
    CopyMem (
 | 
						|
      NewStack,
 | 
						|
      mDepexEvaluationStack,
 | 
						|
      (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (DEPEX_ELEMENT)
 | 
						|
      );
 | 
						|
 | 
						|
    //
 | 
						|
    // Free The Old Stack
 | 
						|
    //
 | 
						|
    FreePool (mDepexEvaluationStack);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Make the Stack pointer point to the old data in the new stack
 | 
						|
  //
 | 
						|
  mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);
 | 
						|
  mDepexEvaluationStack        = NewStack;
 | 
						|
  mDepexEvaluationStackEnd     = NewStack + Size;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Push an element onto the Stack.
 | 
						|
 | 
						|
  @param[in]  Value                  Value to push.
 | 
						|
  @param[in]  Type                   Element Type
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The value was pushed onto the stack.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Wrong stack element type.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Push (
 | 
						|
  IN UINT32   Value,
 | 
						|
  IN UINTN    Type
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  DEPEX_ELEMENT   Element;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check Type
 | 
						|
  //
 | 
						|
  if (Type != BooleanType && Type != VersionType) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check for a stack overflow condition
 | 
						|
  //
 | 
						|
  if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {
 | 
						|
    //
 | 
						|
    // Grow the stack
 | 
						|
    //
 | 
						|
    Status = GrowDepexStack ();
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Element.Value.Version = Value;
 | 
						|
  Element.Type = Type;
 | 
						|
 | 
						|
  //
 | 
						|
  // Push the item onto the stack
 | 
						|
  //
 | 
						|
  *mDepexEvaluationStackPointer = Element;
 | 
						|
  mDepexEvaluationStackPointer++;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Pop an element from the stack.
 | 
						|
 | 
						|
  @param[out]  Element                Element to pop.
 | 
						|
  @param[in]   Type                   Type of element.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The value was popped onto the stack.
 | 
						|
  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Type is mismatched.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Pop (
 | 
						|
  OUT DEPEX_ELEMENT  *Element,
 | 
						|
  IN  ELEMENT_TYPE   Type
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Check for a stack underflow condition
 | 
						|
  //
 | 
						|
  if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EvaluateDependency: Stack underflow!\n"));
 | 
						|
    return EFI_ACCESS_DENIED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Pop the item off the stack
 | 
						|
  //
 | 
						|
  mDepexEvaluationStackPointer--;
 | 
						|
  *Element = *mDepexEvaluationStackPointer;
 | 
						|
  if ((*Element).Type != Type) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EvaluateDependency: Popped element type is mismatched!\n"));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Evaluate the dependencies. The caller must search all the Fmp instances and
 | 
						|
  gather their versions into FmpVersions parameter. If there is PUSH_GUID opcode
 | 
						|
  in dependency expression with no FmpVersions provided, the dependency will
 | 
						|
  evaluate to FALSE.
 | 
						|
 | 
						|
  @param[in]   Dependencies       Dependency expressions.
 | 
						|
  @param[in]   DependenciesSize   Size of Dependency expressions.
 | 
						|
  @param[in]   FmpVersions        Array of Fmp ImageTypeId and version. This
 | 
						|
                                  parameter is optional and can be set to NULL.
 | 
						|
  @param[in]   FmpVersionsCount   Element count of the array. When FmpVersions
 | 
						|
                                  is NULL, FmpVersionsCount must be 0.
 | 
						|
  @param[out]  LastAttemptStatus  An optional pointer to a UINT32 that holds the
 | 
						|
                                  last attempt status to report back to the caller.
 | 
						|
                                  This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS
 | 
						|
                                  if an error code is not set.
 | 
						|
 | 
						|
  @retval TRUE    Dependency expressions evaluate to TRUE.
 | 
						|
  @retval FALSE   Dependency expressions evaluate to FALSE.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
EvaluateDependency (
 | 
						|
  IN  EFI_FIRMWARE_IMAGE_DEP        *Dependencies,
 | 
						|
  IN  UINTN                         DependenciesSize,
 | 
						|
  IN  FMP_DEPEX_CHECK_VERSION_DATA  *FmpVersions,      OPTIONAL
 | 
						|
  IN  UINTN                         FmpVersionsCount,
 | 
						|
  OUT UINT32                        *LastAttemptStatus OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  UINT8                             *Iterator;
 | 
						|
  UINT8                             Index;
 | 
						|
  DEPEX_ELEMENT                     Element1;
 | 
						|
  DEPEX_ELEMENT                     Element2;
 | 
						|
  GUID                              ImageTypeId;
 | 
						|
  UINT32                            Version;
 | 
						|
  UINT32                            LocalLastAttemptStatus;
 | 
						|
 | 
						|
  LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if parameter is valid.
 | 
						|
  //
 | 
						|
  if (Dependencies == NULL || DependenciesSize == 0) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (FmpVersions == NULL && FmpVersionsCount > 0) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
 | 
						|
  // incorrectly formed DEPEX expressions
 | 
						|
  //
 | 
						|
  mDepexEvaluationStackPointer = mDepexEvaluationStack;
 | 
						|
 | 
						|
  Iterator = (UINT8 *) Dependencies->Dependencies;
 | 
						|
  while (Iterator < (UINT8 *) Dependencies->Dependencies + DependenciesSize) {
 | 
						|
    switch (*Iterator)
 | 
						|
    {
 | 
						|
    case EFI_FMP_DEP_PUSH_GUID:
 | 
						|
      if (Iterator + sizeof (EFI_GUID) >= (UINT8 *) Dependencies->Dependencies + DependenciesSize) {
 | 
						|
        DEBUG ((DEBUG_ERROR, "EvaluateDependency: GUID extends beyond end of dependency expression!\n"));
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GUID_BEYOND_DEPEX;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyGuid (&ImageTypeId, (EFI_GUID *) (Iterator + 1));
 | 
						|
      Iterator = Iterator + sizeof (EFI_GUID);
 | 
						|
 | 
						|
      for (Index = 0; Index < FmpVersionsCount; Index ++) {
 | 
						|
        if(CompareGuid (&FmpVersions[Index].ImageTypeId, &ImageTypeId)){
 | 
						|
          Status = Push (FmpVersions[Index].Version, VersionType);
 | 
						|
          if (EFI_ERROR (Status)) {
 | 
						|
            LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
            goto Error;
 | 
						|
          }
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (Index == FmpVersionsCount) {
 | 
						|
        DEBUG ((DEBUG_ERROR, "EvaluateDependency: %g is not found!\n", &ImageTypeId));
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_FMP_NOT_FOUND;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_PUSH_VERSION:
 | 
						|
      if (Iterator + sizeof (UINT32) >= (UINT8 *) Dependencies->Dependencies + DependenciesSize ) {
 | 
						|
        DEBUG ((DEBUG_ERROR, "EvaluateDependency: VERSION extends beyond end of dependency expression!\n"));
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_BEYOND_DEPEX;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
 | 
						|
      Version = *(UINT32 *) (Iterator + 1);
 | 
						|
      Status = Push (Version, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Iterator = Iterator + sizeof (UINT32);
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_VERSION_STR:
 | 
						|
      Iterator += AsciiStrnLenS ((CHAR8 *) Iterator, DependenciesSize - (Iterator - Dependencies->Dependencies));
 | 
						|
      if (Iterator == (UINT8 *) Dependencies->Dependencies + DependenciesSize) {
 | 
						|
        DEBUG ((DEBUG_ERROR, "EvaluateDependency: STRING extends beyond end of dependency expression!\n"));
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_VERSION_STR_BEYOND_DEPEX;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_AND:
 | 
						|
      Status = Pop (&Element1, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Pop (&Element2, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Push (Element1.Value.Boolean & Element2.Value.Boolean, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_OR:
 | 
						|
      Status = Pop (&Element1, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Pop(&Element2, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Push (Element1.Value.Boolean | Element2.Value.Boolean, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_NOT:
 | 
						|
      Status = Pop (&Element1, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Push (!(Element1.Value.Boolean), BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_TRUE:
 | 
						|
      Status = Push (TRUE, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_FALSE:
 | 
						|
      Status = Push (FALSE, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_EQ:
 | 
						|
      Status = Pop (&Element1, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Pop (&Element2, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = (Element1.Value.Version == Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_GT:
 | 
						|
      Status = Pop (&Element1, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Pop (&Element2, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = (Element1.Value.Version >  Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_GTE:
 | 
						|
      Status = Pop (&Element1, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Pop (&Element2, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = (Element1.Value.Version >= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_LT:
 | 
						|
      Status = Pop (&Element1, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Pop (&Element2, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus= LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = (Element1.Value.Version <  Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_LTE:
 | 
						|
      Status = Pop (&Element1, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = Pop (&Element2, VersionType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      Status = (Element1.Value.Version <= Element2.Value.Version) ? Push (TRUE, BooleanType) : Push (FALSE, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_PUSH_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_END:
 | 
						|
      Status = Pop (&Element1, BooleanType);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_POP_FAILURE;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      return Element1.Value.Boolean;
 | 
						|
    default:
 | 
						|
      DEBUG ((DEBUG_ERROR, "EvaluateDependency: Unknown Opcode - %02x!\n", *Iterator));
 | 
						|
      LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_UNKNOWN_OPCODE;
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
    Iterator++;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((DEBUG_ERROR, "EvaluateDependency: No EFI_FMP_DEP_END Opcode in expression!\n"));
 | 
						|
  LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE;
 | 
						|
 | 
						|
Error:
 | 
						|
  if (LastAttemptStatus != NULL) {
 | 
						|
    *LastAttemptStatus = LocalLastAttemptStatus;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Validate the dependency expression and output its size.
 | 
						|
 | 
						|
  @param[in]   Dependencies       Pointer to the EFI_FIRMWARE_IMAGE_DEP.
 | 
						|
  @param[in]   MaxDepexSize       Max size of the dependency.
 | 
						|
  @param[out]  DepexSize          Size of dependency.
 | 
						|
  @param[out]  LastAttemptStatus  An optional pointer to a UINT32 that holds the
 | 
						|
                                  last attempt status to report back to the caller.
 | 
						|
                                  If a last attempt status error code is not returned,
 | 
						|
                                  this function will not modify the LastAttemptStatus value.
 | 
						|
 | 
						|
  @retval TRUE    The dependency expression is valid.
 | 
						|
  @retval FALSE   The dependency expression is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ValidateDependency (
 | 
						|
  IN  EFI_FIRMWARE_IMAGE_DEP  *Dependencies,
 | 
						|
  IN  UINTN                   MaxDepexSize,
 | 
						|
  OUT UINT32                  *DepexSize,
 | 
						|
  OUT UINT32                  *LastAttemptStatus OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8  *Depex;
 | 
						|
 | 
						|
  if (DepexSize != NULL) {
 | 
						|
      *DepexSize = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Dependencies == NULL) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Depex = Dependencies->Dependencies;
 | 
						|
  while (Depex < Dependencies->Dependencies + MaxDepexSize) {
 | 
						|
    switch (*Depex)
 | 
						|
    {
 | 
						|
    case EFI_FMP_DEP_PUSH_GUID:
 | 
						|
      Depex += sizeof (EFI_GUID) + 1;
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_PUSH_VERSION:
 | 
						|
      Depex += sizeof (UINT32) + 1;
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_VERSION_STR:
 | 
						|
      Depex += AsciiStrnLenS ((CHAR8 *) Depex, Dependencies->Dependencies + MaxDepexSize - Depex) + 1;
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_AND:
 | 
						|
    case EFI_FMP_DEP_OR:
 | 
						|
    case EFI_FMP_DEP_NOT:
 | 
						|
    case EFI_FMP_DEP_TRUE:
 | 
						|
    case EFI_FMP_DEP_FALSE:
 | 
						|
    case EFI_FMP_DEP_EQ:
 | 
						|
    case EFI_FMP_DEP_GT:
 | 
						|
    case EFI_FMP_DEP_GTE:
 | 
						|
    case EFI_FMP_DEP_LT:
 | 
						|
    case EFI_FMP_DEP_LTE:
 | 
						|
      Depex += 1;
 | 
						|
      break;
 | 
						|
    case EFI_FMP_DEP_END:
 | 
						|
      Depex += 1;
 | 
						|
      if (DepexSize != NULL) {
 | 
						|
        *DepexSize = (UINT32)(Depex - Dependencies->Dependencies);
 | 
						|
      }
 | 
						|
      return TRUE;
 | 
						|
    default:
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (LastAttemptStatus != NULL) {
 | 
						|
    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_NO_END_OPCODE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get dependency from firmware image.
 | 
						|
 | 
						|
  @param[in]  Image               Points to the firmware image.
 | 
						|
  @param[in]  ImageSize           Size, in bytes, of the firmware image.
 | 
						|
  @param[out] DepexSize           Size, in bytes, of the dependency.
 | 
						|
  @param[out] LastAttemptStatus   An optional pointer to a UINT32 that holds the
 | 
						|
                                  last attempt status to report back to the caller.
 | 
						|
                                  If a last attempt status error code is not returned,
 | 
						|
                                  this function will not modify the LastAttemptStatus value.
 | 
						|
  @retval  The pointer to dependency.
 | 
						|
  @retval  Null
 | 
						|
 | 
						|
**/
 | 
						|
EFI_FIRMWARE_IMAGE_DEP*
 | 
						|
EFIAPI
 | 
						|
GetImageDependency (
 | 
						|
  IN  EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
 | 
						|
  IN  UINTN                             ImageSize,
 | 
						|
  OUT UINT32                            *DepexSize,
 | 
						|
  OUT UINT32                            *LastAttemptStatus  OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FIRMWARE_IMAGE_DEP *Depex;
 | 
						|
  UINTN                  MaxDepexSize;
 | 
						|
 | 
						|
  if (Image == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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) {
 | 
						|
    //
 | 
						|
    // Pointer overflow. Invalid image.
 | 
						|
    //
 | 
						|
    if (LastAttemptStatus != NULL) {
 | 
						|
      *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_LIB_ERROR_GET_DEPEX_FAILURE;
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Depex = (EFI_FIRMWARE_IMAGE_DEP*)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
 | 
						|
  MaxDepexSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the dependency and get the size of dependency
 | 
						|
  //
 | 
						|
  if (ValidateDependency (Depex, MaxDepexSize, DepexSize, LastAttemptStatus)) {
 | 
						|
    return Depex;
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 |