boolean.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,337 行 · 第 1/3 页

C
1,337
字号
/*++

Copyright (c) 2004 - 2005, Intel Corporation                                                         
All rights reserved. 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.             

Module Name:

  Boolean.c

Abstract:

  This routine will evaluate the IFR inconsistency data to determine if
  something is a valid entry for a particular expression

--*/

#include "Ui.h"
#include "Setup.h"

//
// Global stack used to evaluate boolean expresions
//
BOOLEAN *mBooleanEvaluationStack    = (BOOLEAN) 0;
BOOLEAN *mBooleanEvaluationStackEnd = (BOOLEAN) 0;

STATIC
VOID
GrowBooleanStack (
  IN OUT BOOLEAN  **Stack,
  IN     UINTN    StackSizeInBoolean
  )
/*++

Routine Description:

  Grow size of the boolean stack

Arguments:

  Stack     - Old stack on the way in and new stack on the way out

  StackSizeInBoolean - New size of the stack

Returns:

  NONE 

--*/
{
  BOOLEAN *NewStack;

  NewStack = EfiLibAllocatePool (StackSizeInBoolean * sizeof (BOOLEAN));
  ASSERT (NewStack != NULL);

  if (*Stack != NULL) {
    //
    // Copy to Old Stack to the New Stack
    //
    EfiCopyMem (
      NewStack,
      mBooleanEvaluationStack,
      (mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN)
      );

    //
    // Make the Stack pointer point to the old data in the new stack
    //
    *Stack = NewStack + (*Stack - mBooleanEvaluationStack);

    //
    // Free The Old Stack
    //
    gBS->FreePool (mBooleanEvaluationStack);
  }

  mBooleanEvaluationStack     = NewStack;
  mBooleanEvaluationStackEnd  = NewStack + StackSizeInBoolean;
}

VOID
InitializeBooleanEvaluator (
  VOID
  )
/*++

Routine Description:

  Allocate a global stack for boolean processing.

Arguments:

  NONE 

Returns:

  NONE 

--*/
{
  BOOLEAN *NullStack;

  NullStack = NULL;
  GrowBooleanStack (&NullStack, 0x1000);
}

STATIC
VOID
PushBool (
  IN OUT BOOLEAN  **Stack,
  IN BOOLEAN      BoolResult
  )
/*++

Routine Description:

  Push an element onto the Boolean Stack

Arguments:

  Stack      - Current stack location.
  BoolResult - BOOLEAN to push.

Returns:

  None.

--*/
{
  EfiCopyMem (*Stack, &BoolResult, sizeof (BOOLEAN));
  *Stack += 1;

  if (*Stack >= mBooleanEvaluationStackEnd) {
    //
    // If we run out of stack space make a new one that is 2X as big. Copy
    // the old data into the new stack and update Stack to point to the old
    // data in the new stack.
    //
    GrowBooleanStack (
      Stack,
      (mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN) * 2
      );
  }
}

STATIC
BOOLEAN
PopBool (
  IN OUT BOOLEAN **Stack
  )
/*++

Routine Description:

  Pop an element from the Boolean stack.

Arguments:

  Stack - Current stack location

Returns:

  Top of the BOOLEAN stack.

--*/
{
  BOOLEAN ReturnValue;

  *Stack -= 1;
  EfiCopyMem (&ReturnValue, *Stack, sizeof (BOOLEAN));
  return ReturnValue;
}

EFI_STATUS
GrowBooleanExpression (
  IN      EFI_INCONSISTENCY_DATA  *InconsistentTags,
  OUT     VOID                    **BooleanExpression,
  IN OUT  UINTN                   *BooleanExpressionLength
  )
{
  UINT8 *NewExpression;

  NewExpression = EfiLibAllocatePool (*BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA));
  ASSERT (NewExpression != NULL);

  if (*BooleanExpression != NULL) {
    //
    // Copy Old buffer to the New buffer
    //
    EfiCopyMem (NewExpression, *BooleanExpression, *BooleanExpressionLength);

    EfiCopyMem (&NewExpression[*BooleanExpressionLength], InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA));

    //
    // Free The Old buffer
    //
    gBS->FreePool (*BooleanExpression);
  } else {
    //
    // Copy data into new buffer
    //
    EfiCopyMem (NewExpression, InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA));
  }

  *BooleanExpressionLength  = *BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA);
  *BooleanExpression        = (VOID *) NewExpression;
  return EFI_SUCCESS;
}

VOID
CreateBooleanExpression (
  IN  EFI_FILE_FORM_TAGS    *FileFormTags,
  IN  UINT16                Value,
  IN  UINT16                Id,
  IN  BOOLEAN               Complex,
  OUT VOID                  **BooleanExpression,
  OUT UINTN                 *BooleanExpressionLength
  )
/*++

Routine Description:

Arguments:

Returns:

--*/
{
  UINTN                   Count;
  EFI_INCONSISTENCY_DATA  *InconsistentTags;
  EFI_INCONSISTENCY_DATA  FakeInconsistentTags;

  InconsistentTags = FileFormTags->InconsistentTags;

  //
  // Did we run into a question that contains the Id we are looking for?
  //
  for (Count = 0; InconsistentTags->Operand != 0xFF; Count++) {

    //
    // Reserve INVALID_OFFSET_VALUE - 1 for TURE and FALSE, because we need to treat them as well
    // as ideqid etc. but they have no coresponding id, so we reserve this value.
    //
    if (InconsistentTags->QuestionId1 == Id ||
        InconsistentTags->QuestionId1 == INVALID_OFFSET_VALUE - 1) {
      //
      // If !Complex - means evaluate a single if/endif expression
      //
      if (!Complex) {
        //
        // If the ConsistencyId does not match the expression we are looking for
        // skip to the next consistency database entry
        //
        if (InconsistentTags->ConsistencyId != Value) {
          goto NextEntry;
        }
      }
      //
      // We need to rewind to the beginning of the Inconsistent expression
      //
      for (;
           (InconsistentTags->Operand != EFI_IFR_INCONSISTENT_IF_OP) &&
             (InconsistentTags->Operand != EFI_IFR_GRAYOUT_IF_OP) &&
             (InconsistentTags->Operand != EFI_IFR_SUPPRESS_IF_OP);
              ) {
        InconsistentTags = InconsistentTags->Previous;
      }
      //
      // Store the consistency check expression, ensure the next for loop starts at the op-code afterwards
      //
      GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);
      InconsistentTags = InconsistentTags->Next;

      //
      // Keep growing until we hit the End expression op-code or we hit the beginning of another
      // consistency check like grayout/suppress
      //
      for (;
           InconsistentTags->Operand != EFI_IFR_END_IF_OP &&
           InconsistentTags->Operand != EFI_IFR_GRAYOUT_IF_OP &&
           InconsistentTags->Operand != EFI_IFR_SUPPRESS_IF_OP;
            ) {
        GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);
        InconsistentTags = InconsistentTags->Next;
      }
      //
      // Store the EndExpression Op-code
      //
      GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);
    }

NextEntry:
    if (InconsistentTags->Next != NULL) {
      //
      // Skip to next entry
      //
      InconsistentTags = InconsistentTags->Next;
    }
  }

  FakeInconsistentTags.Operand = 0;

  //
  // Add one last expression which will signify we have definitely hit the end
  //
  GrowBooleanExpression (&FakeInconsistentTags, BooleanExpression, BooleanExpressionLength);
}

EFI_STATUS
BooleanVariableWorker (
  IN     CHAR16                   *VariableName,
  IN     EFI_VARIABLE_DEFINITION  *VariableDefinition,
  IN     BOOLEAN                  *StackPtr,
  IN OUT UINTN                    *SizeOfVariable,
  IN OUT VOID                     **VariableData
  )
/*++

Routine Description:


Arguments:

Returns:

--*/
{
  EFI_STATUS  Status;

  Status = gRT->GetVariable (
                  VariableName,
                  &VariableDefinition->Guid,
                  NULL,
                  SizeOfVariable,
                  *VariableData
                  );

  if (EFI_ERROR (Status)) {

    if (Status == EFI_BUFFER_TOO_SMALL) {
      *VariableData = EfiLibAllocatePool (*SizeOfVariable);
      ASSERT (*VariableData != NULL);

      Status = gRT->GetVariable (
                      VariableName,
                      &VariableDefinition->Guid,
                      NULL,
                      SizeOfVariable,
                      *VariableData
                      );
    }

    if (Status == EFI_NOT_FOUND) {
      //
      // This is a serious flaw, we must have some standard result if a variable
      // is not found.  Our default behavior must either be return a TRUE or FALSE
      // since there is nothing else we can really do.  Therefore, my crystal ball
      // says I will return a FALSE
      //
      PushBool (&StackPtr, FALSE);
    }
  }

  return Status;
}

UINT8
PredicateIfrType (
  IN  EFI_INCONSISTENCY_DATA      *Iterator
  )
/*++

Routine Description:
  This routine is for the purpose of predicate whether the Ifr is generated by a VfrCompiler greater than or equal to 1.88 or
  less than 1.88 which is legacy.

Arguments:
  Iterator    - The pointer to inconsistency tags

Returns:

  0x2         - If IFR is not legacy

  0x1         - If IFR is legacy

--*/
{
  //
  // legacy Ifr cover the states:
  // Not ...
  // Operand Opcode Operand
  //
  // while Operand means ideqval, TRUE, or other what can be evaluated to True or False,
  // and Opcode means AND or OR.
  //
  if (Iterator->Operand == EFI_IFR_NOT_OP   ||
      Iterator->Operand == 0) {
    return 0x1;
  } else if (Iterator->Operand == EFI_IFR_EQ_VAR_VAL_OP ||
             Iterator->Operand == EFI_IFR_EQ_ID_VAL_OP  ||
             Iterator->Operand == EFI_IFR_EQ_ID_ID_OP   ||
             Iterator->Operand == EFI_IFR_EQ_ID_LIST_OP) {
    Iterator++;
    if (Iterator->Operand == EFI_IFR_AND_OP ||
        Iterator->Operand == EFI_IFR_OR_OP) {
      Iterator--;
      return 0x1;
    }
    Iterator--;
  }
  return 0x2;
}

VOID
PostOrderEvaluate (
  IN      EFI_FILE_FORM_TAGS          *FileFormTags,
  IN      UINT16                      Width,
  IN OUT  EFI_INCONSISTENCY_DATA      **PIterator,
  IN OUT  BOOLEAN                     **StackPtr
  )
/*++

Routine Description:
  PostOrderEvaluate is used for Ifr generated by VfrCompiler greater than or equal to 1.88,
  which generate Operand Operand Opcode type Ifr.
  PostOrderEvaluete only evaluate boolean expression part, not suppressif/grayoutif. TRUE,
  FALSE, >=, >, (, ) are supported.

Arguments:

  FileFormTags     - The pointer to the tags of the form

  Width            - Width of Operand, recognized every iteration

  PIterator        - The pointer to inconsistency tags

  StackPtr         - The pointer to the evaluation stack

Returns:

  TRUE             - If value is valid

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?