REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the FmpDevicePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			647 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			647 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;
 | 
						|
}
 |