blob: 9d2cab5595d12323c15cdc0ab7f821702ce067a1 [file] [log] [blame]
/** @file
Copyright (c) 2007, 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:
Expression.c
Abstract:
Expression evaluation.
**/
#include <PiDxe.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/UnicodeCollation.h>
#include "UefiIfrParser.h"
//
// Global stack used to evaluate boolean expresions
//
EFI_HII_VALUE *mOpCodeScopeStack = NULL;
EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
#define EXPRESSION_STACK_SIZE_INCREMENT 0x100
/**
Grow size of the stack
@param Stack On input: old stack; On output: new stack
@param StackPtr On input: old stack pointer; On output: new stack
pointer
@param StackPtr On input: old stack end; On output: new stack end
@retval EFI_SUCCESS Grow stack success.
@retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
**/
STATIC
EFI_STATUS
GrowStack (
IN OUT EFI_HII_VALUE **Stack,
IN OUT EFI_HII_VALUE **StackPtr,
IN OUT EFI_HII_VALUE **StackEnd
)
{
UINTN Size;
EFI_HII_VALUE *NewStack;
Size = EXPRESSION_STACK_SIZE_INCREMENT;
if (*StackPtr != NULL) {
Size = Size + (*StackEnd - *Stack);
}
NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
if (NewStack == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (*StackPtr != NULL) {
//
// Copy from Old Stack to the New Stack
//
CopyMem (
NewStack,
*Stack,
(*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
);
//
// Free The Old Stack
//
gBS->FreePool (*Stack);
}
//
// Make the Stack pointer point to the old data in the new stack
//
*StackPtr = NewStack + (*StackPtr - *Stack);
*Stack = NewStack;
*StackEnd = NewStack + Size;
return EFI_SUCCESS;
}
/**
Push an element onto the Boolean Stack
@param Stack On input: old stack; On output: new stack
@param StackPtr On input: old stack pointer; On output: new stack
pointer
@param StackPtr On input: old stack end; On output: new stack end
@param Data Data to push.
@retval EFI_SUCCESS Push stack success.
**/
EFI_STATUS
PushStack (
IN OUT EFI_HII_VALUE **Stack,
IN OUT EFI_HII_VALUE **StackPtr,
IN OUT EFI_HII_VALUE **StackEnd,
IN EFI_HII_VALUE *Data
)
{
EFI_STATUS Status;
//
// Check for a stack overflow condition
//
if (*StackPtr >= *StackEnd) {
//
// Grow the stack
//
Status = GrowStack (Stack, StackPtr, StackEnd);
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Push the item onto the stack
//
CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
*StackPtr = *StackPtr + 1;
return EFI_SUCCESS;
}
/**
Pop an element from the stack.
@param Stack On input: old stack; On output: new stack
@param StackPtr On input: old stack pointer; On output: new stack
pointer
@param StackPtr On input: old stack end; On output: new stack end
@param Data Data to pop.
@retval EFI_SUCCESS The value was popped onto the stack.
@retval EFI_ACCESS_DENIED The pop operation underflowed the stack
**/
EFI_STATUS
PopStack (
IN OUT EFI_HII_VALUE **Stack,
IN OUT EFI_HII_VALUE **StackPtr,
IN OUT EFI_HII_VALUE **StackEnd,
OUT EFI_HII_VALUE *Data
)
{
//
// Check for a stack underflow condition
//
if (*StackPtr == *Stack) {
return EFI_ACCESS_DENIED;
}
//
// Pop the item off the stack
//
*StackPtr = *StackPtr - 1;
CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
return EFI_SUCCESS;
}
/**
Reset stack pointer to begin of the stack.
None.
@return None.
**/
VOID
ResetScopeStack (
VOID
)
{
mOpCodeScopeStackPointer = mOpCodeScopeStack;
}
/**
Push an Operand onto the Stack
@param Operand Operand to push.
@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.
**/
EFI_STATUS
PushScope (
IN UINT8 Operand
)
{
EFI_HII_VALUE Data;
Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
Data.Value.u8 = Operand;
return PushStack (
&mOpCodeScopeStack,
&mOpCodeScopeStackPointer,
&mOpCodeScopeStackEnd,
&Data
);
}
/**
Pop an Operand from the Stack
@param Operand Operand to pop.
@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.
**/
EFI_STATUS
PopScope (
OUT UINT8 *Operand
)
{
EFI_STATUS Status;
EFI_HII_VALUE Data;
Status = PopStack (
&mOpCodeScopeStack,
&mOpCodeScopeStackPointer,
&mOpCodeScopeStackEnd,
&Data
);
*Operand = Data.Value.u8;
return Status;
}
/**
Reset stack pointer to begin of the stack.
None.
@return None.
**/
VOID
ResetExpressionStack (
VOID
)
{
mExpressionEvaluationStackPointer = mExpressionEvaluationStack;
}
/**
Push an Expression value onto the Stack
@param Value Expression value to push.
@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.
**/
EFI_STATUS
PushExpression (
IN EFI_HII_VALUE *Value
)
{
return PushStack (
&mExpressionEvaluationStack,
&mExpressionEvaluationStackPointer,
&mExpressionEvaluationStackEnd,
Value
);
}
/**
Pop an Expression value from the stack.
@param Value Expression value to pop.
@retval EFI_SUCCESS The value was popped onto the stack.
@retval EFI_ACCESS_DENIED The pop operation underflowed the stack
**/
EFI_STATUS
PopExpression (
OUT EFI_HII_VALUE *Value
)
{
return PopStack (
&mExpressionEvaluationStack,
&mExpressionEvaluationStackPointer,
&mExpressionEvaluationStackEnd,
Value
);
}
/**
Zero extend integer/boolean/date/time to UINT64 for comparing.
@param Value HII Value to be converted.
@return None.
**/
VOID
ExtendValueToU64 (
IN EFI_HII_VALUE *Value
)
{
UINT64 Temp;
Temp = 0;
switch (Value->Type) {
case EFI_IFR_TYPE_NUM_SIZE_8:
Temp = Value->Value.u8;
break;
case EFI_IFR_TYPE_NUM_SIZE_16:
Temp = Value->Value.u16;
break;
case EFI_IFR_TYPE_NUM_SIZE_32:
Temp = Value->Value.u32;
break;
case EFI_IFR_TYPE_BOOLEAN:
Temp = Value->Value.b;
break;
case EFI_IFR_TYPE_TIME:
Temp = Value->Value.u32 & 0xffffff;
break;
case EFI_IFR_TYPE_DATE:
Temp = Value->Value.u32;
break;
default:
return;
}
Value->Value.u64 = Temp;
}