From be69cab686d51f93e7fd26a1d07b27e2fa103531 Mon Sep 17 00:00:00 2001
From: Eric Dong <eric.dong@intel.com>
Date: Thu, 30 Apr 2015 13:52:49 +0800
Subject: [Patch 1/2] BaseTools: Enhance the check for numeric opcode with
 EFI_IFR_DISPLAY_INT_DEC attribute.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Eric Dong <eric.dong@intel.com>
---
 BaseTools/Source/C/VfrCompile/VfrFormPkg.h |   8 ++
 BaseTools/Source/C/VfrCompile/VfrSyntax.g  | 170 +++++++++++++++++++++++++----
 2 files changed, 156 insertions(+), 22 deletions(-)

diff --git a/BaseTools/Source/C/VfrCompile/VfrFormPkg.h b/BaseTools/Source/C/VfrCompile/VfrFormPkg.h
index 3d2def8..e64ef1b 100644
--- a/BaseTools/Source/C/VfrCompile/VfrFormPkg.h
+++ b/BaseTools/Source/C/VfrCompile/VfrFormPkg.h
@@ -308,10 +308,14 @@ public:
   }
 
   VOID UpdateHeader (IN EFI_IFR_OP_HEADER *Header) {
     mHeader = Header;
   }
+
+  UINT8 GetOpCode () {
+    return mHeader->OpCode;
+  }
 };
 
 extern UINT8 gScopeCount;
 
 /*
@@ -1356,10 +1360,14 @@ public:
     } else {
       mNumeric->Flags = LFlags;
     }
     return VFR_RETURN_SUCCESS;
   }
+
+  UINT8 GetNumericFlags () {
+    return mNumeric->Flags;
+  }
 };
 
 class CIfrOneOf : public CIfrObj, public CIfrOpHeader, public CIfrQuestionHeader, public CIfrMinMaxStepData {
 private:
   EFI_IFR_ONE_OF *mOneOf;
diff --git a/BaseTools/Source/C/VfrCompile/VfrSyntax.g b/BaseTools/Source/C/VfrCompile/VfrSyntax.g
index 2255d6f..d014aff 100644
--- a/BaseTools/Source/C/VfrCompile/VfrSyntax.g
+++ b/BaseTools/Source/C/VfrCompile/VfrSyntax.g
@@ -1394,24 +1394,40 @@ vfrQuestionDataFieldName [EFI_QUESTION_ID &QId, UINT32 &Mask, CHAR8 *&VarIdStr,
   ;
 
 vfrConstantValueField[UINT8 Type] > [EFI_IFR_TYPE_VALUE Value] :
   <<
     EFI_GUID Guid;
+    BOOLEAN  Negative = FALSE;
   >>
+    {
+      "\-"                                          << Negative = TRUE;  >>
+    }
     N1:Number                                       <<
                                                        switch ($Type) {
                                                        case EFI_IFR_TYPE_NUM_SIZE_8 :
-                                                         $Value.u8     = _STOU8(N1->getText(), N1->getLine());
+                                                         $Value.u8 = _STOU8(N1->getText(), N1->getLine());
+                                                         if (Negative) {
+                                                           $Value.u8 = ~$Value.u8 + 1;
+                                                         }
                                                        break;
                                                        case EFI_IFR_TYPE_NUM_SIZE_16 :
-                                                         $Value.u16    = _STOU16(N1->getText(), N1->getLine());
+                                                         $Value.u16 = _STOU16(N1->getText(), N1->getLine());
+                                                         if (Negative) {
+                                                           $Value.u16 = ~$Value.u16 + 1;
+                                                         }
                                                        break;
                                                        case EFI_IFR_TYPE_NUM_SIZE_32 :
                                                          $Value.u32    = _STOU32(N1->getText(), N1->getLine());
+                                                         if (Negative) {
+                                                           $Value.u32 = ~$Value.u32 + 1;
+                                                         }
                                                        break;
                                                        case EFI_IFR_TYPE_NUM_SIZE_64 :
                                                          $Value.u64    = _STOU64(N1->getText(), N1->getLine());
+                                                         if (Negative) {
+                                                           $Value.u64 = ~$Value.u64 + 1;
+                                                         }
                                                        break;
                                                        case EFI_IFR_TYPE_BOOLEAN :
                                                          $Value.b      = _STOU8(N1->getText(), N1->getLine());
                                                        break;
                                                        case EFI_IFR_TYPE_STRING :
@@ -1531,20 +1547,53 @@ vfrStatementDefault :
      EFI_DEFAULT_ID        DefaultId     = EFI_HII_DEFAULT_CLASS_STANDARD;
      CHAR8                 *VarStoreName = NULL;
      EFI_VFR_VARSTORE_TYPE VarStoreType  = EFI_VFR_VARSTORE_INVALID;
      UINT32                Size          = 0;
      EFI_GUID              *VarGuid      = NULL;
+     CIfrNumeric           *NumericQst   = NULL;
   >>
   D:Default                                         
   (
     (
       "=" vfrConstantValueField[_GET_CURRQEST_DATATYPE()] > [Val] ","  
                                                     << 
                                                         if (gCurrentMinMaxData != NULL && gCurrentMinMaxData->IsNumericOpcode()) {
                                                           //check default value is valid for Numeric Opcode
-                                                          if (Val.u64 < gCurrentMinMaxData->GetMinData(_GET_CURRQEST_DATATYPE()) || Val.u64 > gCurrentMinMaxData->GetMaxData(_GET_CURRQEST_DATATYPE())) {
-                                                            _PCATCH (VFR_RETURN_INVALID_PARAMETER, D->getLine(), "Numeric default value must be between MinValue and MaxValue.");
+                                                          NumericQst = (CIfrNumeric *) gCurrentQuestion;
+                                                          if ((NumericQst->GetNumericFlags() & EFI_IFR_DISPLAY) == 0) {
+                                                            switch (_GET_CURRQEST_DATATYPE()) {
+                                                            case EFI_IFR_TYPE_NUM_SIZE_8:
+                                                              if (((INT8) Val.u8 < (INT8) gCurrentMinMaxData->GetMinData(_GET_CURRQEST_DATATYPE())) || 
+                                                                  ((INT8) Val.u8 > (INT8) gCurrentMinMaxData->GetMaxData(_GET_CURRQEST_DATATYPE()))) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, D->getLine(), "Numeric default value must be between MinValue and MaxValue.");
+                                                              }
+                                                              break;
+                                                            case EFI_IFR_TYPE_NUM_SIZE_16:
+                                                              if (((INT16) Val.u16 < (INT16) gCurrentMinMaxData->GetMinData(_GET_CURRQEST_DATATYPE())) || 
+                                                                  ((INT16) Val.u16 > (INT16) gCurrentMinMaxData->GetMaxData(_GET_CURRQEST_DATATYPE()))) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, D->getLine(), "Numeric default value must be between MinValue and MaxValue.");
+                                                              }
+                                                              break;
+                                                            case EFI_IFR_TYPE_NUM_SIZE_32:
+                                                              if (((INT32) Val.u32 < (INT32) gCurrentMinMaxData->GetMinData(_GET_CURRQEST_DATATYPE())) || 
+                                                                  ((INT32) Val.u32 > (INT32) gCurrentMinMaxData->GetMaxData(_GET_CURRQEST_DATATYPE()))) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, D->getLine(), "Numeric default value must be between MinValue and MaxValue.");
+                                                              }
+                                                              break;
+                                                            case EFI_IFR_TYPE_NUM_SIZE_64:
+                                                              if (((INT64) Val.u64 < (INT64) gCurrentMinMaxData->GetMinData(_GET_CURRQEST_DATATYPE())) || 
+                                                                  ((INT64) Val.u64 > (INT64) gCurrentMinMaxData->GetMaxData(_GET_CURRQEST_DATATYPE()))) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, D->getLine(), "Numeric default value must be between MinValue and MaxValue.");
+                                                              }
+                                                              break;
+                                                            default:
+                                                              break;
+                                                            }
+                                                          } else {
+                                                            if (Val.u64 < gCurrentMinMaxData->GetMinData(_GET_CURRQEST_DATATYPE()) || Val.u64 > gCurrentMinMaxData->GetMaxData(_GET_CURRQEST_DATATYPE())) {
+                                                              _PCATCH (VFR_RETURN_INVALID_PARAMETER, D->getLine(), "Numeric default value must be between MinValue and MaxValue.");
+                                                            }
                                                           }
                                                         }
                                                         if (_GET_CURRQEST_DATATYPE() == EFI_IFR_TYPE_OTHER) {
                                                           _PCATCH (VFR_RETURN_FATAL_ERROR, D->getLine(), "Default data type error.");
                                                           Size = sizeof (EFI_IFR_TYPE_VALUE);
@@ -2218,45 +2267,122 @@ vfrSetMinMaxStep[CIfrMinMaxStepData & MMSDObj] :
   <<
      UINT64 MaxU8 = 0, MinU8 = 0, StepU8 = 0;
      UINT32 MaxU4 = 0, MinU4 = 0, StepU4 = 0;
      UINT16 MaxU2 = 0, MinU2 = 0, StepU2 = 0;
      UINT8  MaxU1 = 0, MinU1 = 0, StepU1 = 0;
+     BOOLEAN IntDecStyle = FALSE;
+     CIfrNumeric *NObj = (CIfrNumeric *) (&MMSDObj);
+     if ((NObj->GetOpCode() == EFI_IFR_NUMERIC_OP) && ((NObj->GetNumericFlags() & EFI_IFR_DISPLAY) == 0)) {
+       IntDecStyle = TRUE;
+     }
+     BOOLEAN MinNegative = FALSE;
+     BOOLEAN MaxNegative = FALSE;
   >>
-  Minimum   "=" I:Number ","
-                                                       <<
+  Minimum   "=" 
+  {
+    "\-"                                               << MinNegative = TRUE; >>
+  }
+  I:Number ","                                         <<
+                                                          if (!IntDecStyle &&  MinNegative) {
+                                                            _PCATCH (VFR_RETURN_INVALID_PARAMETER, I->getLine(), "\"-\" can't be used when not in int decimal type. ");
+                                                          }
                                                           switch (_GET_CURRQEST_DATATYPE()) {
-                                                          case EFI_IFR_TYPE_NUM_SIZE_64 : MinU8 = _STOU64(I->getText(), I->getLine()); break;
-                                                          case EFI_IFR_TYPE_NUM_SIZE_32 : MinU4 = _STOU32(I->getText(), I->getLine()); break;
-                                                          case EFI_IFR_TYPE_NUM_SIZE_16 : MinU2 = _STOU16(I->getText(), I->getLine()); break;
-                                                          case EFI_IFR_TYPE_NUM_SIZE_8 :  MinU1 = _STOU8(I->getText(), I->getLine());  break;
+                                                          case EFI_IFR_TYPE_NUM_SIZE_64 :
+                                                            MinU8 = _STOU64(I->getText(), I->getLine());
+                                                            if (MinNegative) {
+                                                              MinU8 = ~MinU8 + 1;
+                                                            }
+                                                            break;
+                                                          case EFI_IFR_TYPE_NUM_SIZE_32 :
+                                                            MinU4 = _STOU32(I->getText(), I->getLine());
+                                                            if (MinNegative) {
+                                                              MinU4 = ~MinU4 + 1;
+                                                            }
+                                                            break;
+                                                          case EFI_IFR_TYPE_NUM_SIZE_16 :
+                                                            MinU2 = _STOU16(I->getText(), I->getLine());
+                                                            if (MinNegative) {
+                                                              MinU2 = ~MinU2 + 1;
+                                                            }
+                                                            break;
+                                                          case EFI_IFR_TYPE_NUM_SIZE_8 :
+                                                            MinU1 = _STOU8(I->getText(), I->getLine());
+                                                            if (MinNegative) {
+                                                              MinU1 = ~MinU1 + 1;
+                                                            }
+                                                            break;
                                                           }
                                                        >>
-  Maximum   "=" A:Number ","
-                                                       <<
+  Maximum   "=" 
+  { 
+    "\-"                                               << MaxNegative = TRUE; >>
+  }
+  A:Number ","                                         <<
+                                                          if (!IntDecStyle &&  MaxNegative) {
+                                                            _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "\"-\" can't be used when not in int decimal type. ");
+                                                          }
+
                                                           switch (_GET_CURRQEST_DATATYPE()) {
                                                           case EFI_IFR_TYPE_NUM_SIZE_64 : 
                                                             MaxU8 = _STOU64(A->getText(), A->getLine()); 
-                                                            if (MaxU8 < MinU8) {
-                                                              _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                            if (MaxNegative) {
+                                                              MaxU8 = ~MaxU8 + 1;
+                                                            }
+                                                            if (IntDecStyle) {
+                                                              if ((INT64) MaxU8 < (INT64) MinU8) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
+                                                            } else {
+                                                              if (MaxU8 < MinU8) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
                                                             }
                                                             break;
                                                           case EFI_IFR_TYPE_NUM_SIZE_32 : 
-                                                            MaxU4 = _STOU32(A->getText(), A->getLine()); 
-                                                            if (MaxU4 < MinU4) {
-                                                              _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                            MaxU4 = _STOU32(A->getText(), A->getLine());
+                                                            if (MaxNegative) {
+                                                              MaxU4 = ~MaxU4 + 1;
+                                                            }
+                                                            if (IntDecStyle) {
+                                                              if ((INT32) MaxU4 < (INT32) MinU4) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
+                                                            } else {
+                                                              if (MaxU4 < MinU4) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
                                                             }
                                                             break;
                                                           case EFI_IFR_TYPE_NUM_SIZE_16 : 
                                                             MaxU2 = _STOU16(A->getText(), A->getLine()); 
-                                                            if (MaxU2 < MinU2) {
-                                                              _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                            if (MaxNegative) {
+                                                              MaxU2 = ~MaxU2 + 1;
+                                                            }
+
+                                                            if (IntDecStyle) {
+                                                              if ((INT16) MaxU2 < (INT16) MinU2) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
+                                                            } else {
+                                                              if (MaxU2 < MinU2) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
                                                             }
                                                             break;
                                                           case EFI_IFR_TYPE_NUM_SIZE_8 :  
-                                                            MaxU1 = _STOU8(A->getText(), A->getLine());  
-                                                            if (MaxU1 < MinU1) {
-                                                              _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                            MaxU1 = _STOU8(A->getText(), A->getLine());
+                                                            if (MaxNegative) {
+                                                              MaxU1 = ~MaxU1 + 1;
+                                                            }
+                                                            if (IntDecStyle) {
+                                                              if ((INT8) MaxU1 < (INT8) MinU1) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
+                                                            } else {
+                                                              if (MaxU1 < MinU1) {
+                                                                _PCATCH (VFR_RETURN_INVALID_PARAMETER, A->getLine(), "Maximum can't be less than Minimum");
+                                                              }
                                                             }
                                                             break;
                                                           }
                                                        >>
   {
-- 
1.9.5.msysgit.1

