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;
 | |
| }
 |