/** @file | |
Copyright (c) 2007 - 2010, 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. | |
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 StackEnd 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. | |
**/ | |
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 StackEnd 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 StackEnd 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. | |
**/ | |
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. | |
**/ | |
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; | |
} |