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