mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-03 21:17:23 +01:00 
			
		
		
		
	1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			254 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  PEI Dispatcher Dependency Evaluator
 | 
						|
 | 
						|
  This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
 | 
						|
  if a driver can be scheduled for execution.  The criteria for
 | 
						|
  schedulability is that the dependency expression is satisfied.
 | 
						|
 | 
						|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "PeiMain.h"
 | 
						|
#include "Dependency.h"
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This routine determines if a PPI has been installed.
 | 
						|
  The truth value of a GUID is determined by if the PPI has
 | 
						|
  been published and can be queried from the PPI database.
 | 
						|
 | 
						|
 | 
						|
  @param PeiServices     An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
 | 
						|
  @param Stack           Reference to EVAL_STACK_ENTRY that contains PPI GUID to check
 | 
						|
 | 
						|
  @retval TRUE  if the PPI is already installed.
 | 
						|
  @retval FALSE if the PPI has yet to be installed.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsPpiInstalled (
 | 
						|
  IN EFI_PEI_SERVICES  **PeiServices,
 | 
						|
  IN EVAL_STACK_ENTRY  *Stack
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID        *PeiInstance;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EFI_GUID    PpiGuid;
 | 
						|
 | 
						|
  //
 | 
						|
  // If there is no GUID to evaluate, just return current result on stack.
 | 
						|
  //
 | 
						|
  if (Stack->Operator == NULL) {
 | 
						|
    return Stack->Result;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the Guid into a locale variable so that there are no
 | 
						|
  // possibilities of alignment faults for cross-compilation
 | 
						|
  // environments such as Intel?Itanium(TM).
 | 
						|
  //
 | 
						|
  CopyMem(&PpiGuid, Stack->Operator, sizeof(EFI_GUID));
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if the PPI is installed.
 | 
						|
  //
 | 
						|
  Status = PeiServicesLocatePpi(
 | 
						|
             &PpiGuid,        // GUID
 | 
						|
             0,               // INSTANCE
 | 
						|
             NULL,            // EFI_PEI_PPI_DESCRIPTOR
 | 
						|
             &PeiInstance     // PPI
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This is the POSTFIX version of the dependency evaluator.  When a
 | 
						|
  PUSH [PPI GUID] is encountered, a pointer to the GUID is stored on
 | 
						|
  the evaluation stack.  When that entry is poped from the evaluation
 | 
						|
  stack, the PPI is checked if it is installed.  This method allows
 | 
						|
  some time savings as not all PPIs must be checked for certain
 | 
						|
  operation types (AND, OR).
 | 
						|
 | 
						|
 | 
						|
  @param PeiServices            An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
 | 
						|
  @param DependencyExpression   Pointer to a dependency expression.  The Grammar adheres to
 | 
						|
                                the BNF described above and is stored in postfix notation.
 | 
						|
 | 
						|
  @retval TRUE      if it is a well-formed Grammar
 | 
						|
  @retval FALSE     if the dependency expression overflows the evaluation stack
 | 
						|
                    if the dependency expression underflows the evaluation stack
 | 
						|
                    if the dependency expression is not a well-formed Grammar.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
PeimDispatchReadiness (
 | 
						|
  IN EFI_PEI_SERVICES   **PeiServices,
 | 
						|
  IN VOID               *DependencyExpression
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEPENDENCY_EXPRESSION_OPERAND  *Iterator;
 | 
						|
  EVAL_STACK_ENTRY               *StackPtr;
 | 
						|
  EVAL_STACK_ENTRY               EvalStack[MAX_GRAMMAR_SIZE];
 | 
						|
 | 
						|
  Iterator  = DependencyExpression;
 | 
						|
 | 
						|
  StackPtr = EvalStack;
 | 
						|
 | 
						|
  while (TRUE) {
 | 
						|
 | 
						|
    switch (*(Iterator++)) {
 | 
						|
 | 
						|
      //
 | 
						|
      // For performance reason we put the frequently used items in front of
 | 
						|
      // the rarely used  items
 | 
						|
      //
 | 
						|
 | 
						|
      case (EFI_DEP_PUSH):
 | 
						|
        //
 | 
						|
        // Check to make sure the dependency grammar doesn't overflow the
 | 
						|
        // EvalStack on the push
 | 
						|
        //
 | 
						|
        if (StackPtr > &EvalStack[MAX_GRAMMAR_SIZE-1]) {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE (Underflow Error)\n"));
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Push the pointer to the PUSH opcode operator (pointer to PPI GUID)
 | 
						|
        // We will evaluate if the PPI is insalled on the POP operation.
 | 
						|
        //
 | 
						|
        StackPtr->Operator = (VOID *) Iterator;
 | 
						|
        Iterator = Iterator + sizeof (EFI_GUID);
 | 
						|
        DEBUG ((DEBUG_DISPATCH, "  PUSH GUID(%g) = %a\n", StackPtr->Operator, IsPpiInstalled (PeiServices, StackPtr) ? "TRUE" : "FALSE"));
 | 
						|
        StackPtr++;
 | 
						|
        break;
 | 
						|
 | 
						|
      case (EFI_DEP_AND):
 | 
						|
      case (EFI_DEP_OR):
 | 
						|
        if (*(Iterator - 1) == EFI_DEP_AND) {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  AND\n"));
 | 
						|
        } else {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  OR\n"));
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Check to make sure the dependency grammar doesn't underflow the
 | 
						|
        // EvalStack on the two POPs for the AND operation.  Don't need to
 | 
						|
        // check for the overflow on PUSHing the result since we already
 | 
						|
        // did two POPs.
 | 
						|
        //
 | 
						|
        if (StackPtr < &EvalStack[2]) {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE (Underflow Error)\n"));
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Evaluate the first POPed operator only. If the operand is
 | 
						|
        // EFI_DEP_AND and the POPed operator evaluates to FALSE, or the
 | 
						|
        // operand is EFI_DEP_OR and the POPed operator evaluates to TRUE,
 | 
						|
        // we don't need to check the second operator, and the result will be
 | 
						|
        // evaluation of the POPed operator. Otherwise, don't POP the second
 | 
						|
        // operator since it will now evaluate to the final result on the
 | 
						|
        // next operand that causes a POP.
 | 
						|
        //
 | 
						|
        StackPtr--;
 | 
						|
        //
 | 
						|
        // Iterator has increased by 1 after we retrieve the operand, so here we
 | 
						|
        // should get the value pointed by (Iterator - 1), in order to obtain the
 | 
						|
        // same operand.
 | 
						|
        //
 | 
						|
        if (*(Iterator - 1) == EFI_DEP_AND) {
 | 
						|
          if (!(IsPpiInstalled (PeiServices, StackPtr))) {
 | 
						|
            (StackPtr-1)->Result = FALSE;
 | 
						|
            (StackPtr-1)->Operator = NULL;
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          if (IsPpiInstalled (PeiServices, StackPtr)) {
 | 
						|
            (StackPtr-1)->Result = TRUE;
 | 
						|
            (StackPtr-1)->Operator = NULL;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case (EFI_DEP_END):
 | 
						|
        DEBUG ((DEBUG_DISPATCH, "  END\n"));
 | 
						|
        StackPtr--;
 | 
						|
        //
 | 
						|
        // Check to make sure EvalStack is balanced.  If not, then there is
 | 
						|
        // an error in the dependency grammar, so return EFI_INVALID_PARAMETER.
 | 
						|
        //
 | 
						|
        if (StackPtr != &EvalStack[0]) {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE (Underflow Error)\n"));
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
        DEBUG ((DEBUG_DISPATCH, "  RESULT = %a\n", IsPpiInstalled (PeiServices, StackPtr) ? "TRUE" : "FALSE"));
 | 
						|
        return IsPpiInstalled (PeiServices, StackPtr);
 | 
						|
 | 
						|
      case (EFI_DEP_NOT):
 | 
						|
        DEBUG ((DEBUG_DISPATCH, "  NOT\n"));
 | 
						|
        //
 | 
						|
        // Check to make sure the dependency grammar doesn't underflow the
 | 
						|
        // EvalStack on the POP for the NOT operation.  Don't need to
 | 
						|
        // check for the overflow on PUSHing the result since we already
 | 
						|
        // did a POP.
 | 
						|
        //
 | 
						|
        if (StackPtr < &EvalStack[1]) {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE (Underflow Error)\n"));
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
        (StackPtr-1)->Result = (BOOLEAN) !IsPpiInstalled (PeiServices, (StackPtr-1));
 | 
						|
        (StackPtr-1)->Operator = NULL;
 | 
						|
        break;
 | 
						|
 | 
						|
      case (EFI_DEP_TRUE):
 | 
						|
      case (EFI_DEP_FALSE):
 | 
						|
        if (*(Iterator - 1) == EFI_DEP_TRUE) {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  TRUE\n"));
 | 
						|
        } else {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  FALSE\n"));
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Check to make sure the dependency grammar doesn't overflow the
 | 
						|
        // EvalStack on the push
 | 
						|
        //
 | 
						|
        if (StackPtr > &EvalStack[MAX_GRAMMAR_SIZE-1]) {
 | 
						|
          DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE (Underflow Error)\n"));
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Iterator has increased by 1 after we retrieve the operand, so here we
 | 
						|
        // should get the value pointed by (Iterator - 1), in order to obtain the
 | 
						|
        // same operand.
 | 
						|
        //
 | 
						|
        if (*(Iterator - 1) == EFI_DEP_TRUE) {
 | 
						|
          StackPtr->Result = TRUE;
 | 
						|
        } else {
 | 
						|
          StackPtr->Result = FALSE;
 | 
						|
        }
 | 
						|
        StackPtr->Operator = NULL;
 | 
						|
        StackPtr++;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE (Invalid opcode)\n"));
 | 
						|
        //
 | 
						|
        // The grammar should never arrive here
 | 
						|
        //
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |