Reviewed-by: jiewen....@intel.com

-----Original Message-----
From: Zeng, Star 
Sent: Tuesday, August 18, 2015 8:29 PM
To: edk2-devel@lists.01.org
Cc: Yao, Jiewen
Subject: [PATCH] MdeModulePkg: Add VarCheckHiiLib NULL class library

The check will be based on VarCheckHiiBin that generated
from FV and Hii Database.

Cc: Jiewen Yao <jiewen....@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.z...@intel.com>
---
 .../VarCheckHiiLib/InternalVarCheckStructure.h     |   82 ++
 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h  |   63 +
 .../Library/VarCheckHiiLib/VarCheckHiiGen.c        | 1483 ++++++++++++++++++++
 .../Library/VarCheckHiiLib/VarCheckHiiGen.h        |  136 ++
 .../Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c  |  443 ++++++
 .../Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c |   73 +
 .../Library/VarCheckHiiLib/VarCheckHiiLib.inf      |   58 +
 .../Library/VarCheckHiiLib/VarCheckHiiLib.uni      |  Bin 0 -> 1766 bytes
 .../VarCheckHiiLib/VarCheckHiiLibNullClass.c       |  539 +++++++
 MdeModulePkg/MdeModulePkg.dec                      |    6 +
 MdeModulePkg/MdeModulePkg.dsc                      |    3 +
 MdeModulePkg/MdeModulePkg.uni                      |  Bin 182392 -> 183916 
bytes
 12 files changed, 2886 insertions(+)
 create mode 100644 
MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h
 create mode 100644 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
 create mode 100644 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
 create mode 100644 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
 create mode 100644 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
 create mode 100644 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
 create mode 100644 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
 create mode 100644 MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni
 create mode 100644 
MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c

diff --git a/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h 
b/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h
new file mode 100644
index 0000000..a9faed4
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h
@@ -0,0 +1,82 @@
+/** @file
+  Internal structure for Var Check Hii.
+
+Copyright (c) 2015, 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.
+
+**/
+
+#ifndef _VAR_CHECK_STRUCTURE_H_
+#define _VAR_CHECK_STRUCTURE_H_
+
+//
+// Alignment for Hii Variable and Question header.
+//
+#define HEADER_ALIGNMENT  4
+#define HEADER_ALIGN(Header)  (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & 
(~(HEADER_ALIGNMENT - 1)))
+
+#pragma pack (1)
+
+#define VAR_CHECK_HII_REVISION  0x0001
+
+typedef struct {
+  UINT16            Revision;
+  UINT16            HeaderLength;
+  UINT32            Length; // Length include this header
+  UINT8             OpCode;
+  UINT8             Reserved;
+  UINT16            Size;
+  UINT32            Attributes;
+  EFI_GUID          Guid;
+//CHAR16              Name[];
+} VAR_CHECK_HII_VARIABLE_HEADER;
+
+typedef struct {
+  UINT8             OpCode;
+  UINT8             Length; // Length include this header
+  UINT16            VarOffset;
+  UINT8             StorageWidth;
+} VAR_CHECK_HII_QUESTION_HEADER;
+
+typedef struct {
+  UINT8             OpCode;
+  UINT8             Length; // Length include this header
+  UINT16            VarOffset;
+  UINT8             StorageWidth;
+//UINTx               Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_ONEOF;
+
+typedef struct {
+  UINT8             OpCode;
+  UINT8             Length; // Length include this header
+  UINT16            VarOffset;
+  UINT8             StorageWidth;
+} VAR_CHECK_HII_QUESTION_CHECKBOX;
+
+typedef struct {
+  UINT8             OpCode;
+  UINT8             Length; // Length include this header
+  UINT16            VarOffset;
+  UINT8             StorageWidth;
+//UINTx               Minimum; // x = UINT8/UINT16/UINT32/UINT64;
+//UINTx               Maximum; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_NUMERIC;
+
+typedef struct {
+  UINT8             OpCode;
+  UINT8             Length; // Length include this header
+  UINT16            VarOffset;
+  UINT8             StorageWidth;
+  UINT8             MaxContainers;
+//UINTx               Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_ORDEREDLIST;
+
+#pragma pack ()
+
+#endif
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
new file mode 100644
index 0000000..d770785
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
@@ -0,0 +1,63 @@
+/** @file
+  Include file for Var Check Hii handler and bin.
+
+Copyright (c) 2015, 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.
+
+**/
+
+#ifndef _VAR_CHECK_HII_H_
+#define _VAR_CHECK_HII_H_
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/ZeroGuid.h>
+
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include "InternalVarCheckStructure.h"
+#include "VarCheckHiiGen.h"
+
+//#define DUMP_VAR_CHECK_HII
+//#define DUMP_HII_DATA
+
+typedef struct {
+  UINT8     HiiOpCode;
+  CHAR8     *HiiOpCodeStr;
+} VAR_CHECK_HII_OPCODE_STRING;
+
+typedef struct {
+  UINT8     PackageType;
+  CHAR8     *PackageTypeStr;
+} VAR_CHECK_HII_PACKAGE_TYPE_STRING;
+
+/**
+  Dump Var Check HII.
+
+  @param[in] VarCheckHiiBin     Pointer to VarCheckHiiBin.
+  @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
+
+**/
+VOID
+DumpVarCheckHii (
+  IN VOID   *VarCheckHiiBin,
+  IN UINTN  VarCheckHiiBinSize
+  );
+
+extern VAR_CHECK_HII_VARIABLE_HEADER    *mVarCheckHiiBin;
+extern UINTN                            mVarCheckHiiBinSize;
+
+#endif
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
new file mode 100644
index 0000000..725ccc7
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
@@ -0,0 +1,1483 @@
+/** @file
+  Var Check Hii bin generation.
+
+Copyright (c) 2015, 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 "VarCheckHiiGen.h"
+
+LIST_ENTRY mVarCheckHiiList = INITIALIZE_LIST_HEAD_VARIABLE (mVarCheckHiiList);
+
+#define VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE   SIGNATURE_32 ('V', 'C', 'H', 
'V')
+
+typedef struct {
+  UINTN                         Signature;
+  LIST_ENTRY                    Link;
+  VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+  EFI_VARSTORE_ID               VarStoreId;
+
+  VAR_CHECK_HII_QUESTION_HEADER **HiiQuestionArray;
+} VAR_CHECK_HII_VARIABLE_NODE;
+
+#define VAR_CHECK_HII_VARIABLE_FROM_LINK(a) CR (a, 
VAR_CHECK_HII_VARIABLE_NODE, Link, VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE)
+
+CHAR16 *mVarName = NULL;
+UINTN  mMaxVarNameSize = 0;
+
+#ifdef DUMP_HII_DATA
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING   
mIfrOpCodeStringTable[] = {
+  {EFI_IFR_VARSTORE_OP,             "EFI_IFR_VARSTORE_OP"},
+  {EFI_IFR_VARSTORE_EFI_OP,         "EFI_IFR_VARSTORE_EFI_OP"},
+  {EFI_IFR_ONE_OF_OP,               "EFI_IFR_ONE_OF_OP"},
+  {EFI_IFR_CHECKBOX_OP,             "EFI_IFR_CHECKBOX_OP"},
+  {EFI_IFR_NUMERIC_OP,              "EFI_IFR_NUMERIC_OP"},
+  {EFI_IFR_ORDERED_LIST_OP,         "EFI_IFR_ORDERED_LIST_OP"},
+  {EFI_IFR_ONE_OF_OPTION_OP,        "EFI_IFR_ONE_OF_OPTION_OP"},
+};
+
+/**
+  Ifr opcode to string.
+
+  @param[in] IfrOpCode  Ifr OpCode.
+
+  @return Pointer to string.
+
+**/
+CHAR8 *
+IfrOpCodeToStr (
+  IN UINT8  IfrOpCode
+  )
+{
+  UINTN  Index;
+  for (Index = 0; Index < sizeof (mIfrOpCodeStringTable) / sizeof 
(mIfrOpCodeStringTable[0]); Index++) {
+    if (mIfrOpCodeStringTable[Index].HiiOpCode == IfrOpCode) {
+      return mIfrOpCodeStringTable[Index].HiiOpCodeStr;
+    }
+  }
+
+  return "<UnknownIfrOpCode>";
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_PACKAGE_TYPE_STRING  
mPackageTypeStringTable[] = {
+  {EFI_HII_PACKAGE_TYPE_ALL,            "EFI_HII_PACKAGE_TYPE_ALL"},
+  {EFI_HII_PACKAGE_TYPE_GUID,           "EFI_HII_PACKAGE_TYPE_GUID"},
+  {EFI_HII_PACKAGE_FORMS,               "EFI_HII_PACKAGE_FORMS"},
+  {EFI_HII_PACKAGE_STRINGS,             "EFI_HII_PACKAGE_STRINGS"},
+  {EFI_HII_PACKAGE_FONTS,               "EFI_HII_PACKAGE_FONTS"},
+  {EFI_HII_PACKAGE_IMAGES,              "EFI_HII_PACKAGE_IMAGES"},
+  {EFI_HII_PACKAGE_SIMPLE_FONTS,        "EFI_HII_PACKAGE_SIMPLE_FONTS"},
+  {EFI_HII_PACKAGE_DEVICE_PATH,         "EFI_HII_PACKAGE_DEVICE_PATH"},
+  {EFI_HII_PACKAGE_KEYBOARD_LAYOUT,     "EFI_HII_PACKAGE_KEYBOARD_LAYOUT"},
+  {EFI_HII_PACKAGE_ANIMATIONS,          "EFI_HII_PACKAGE_ANIMATIONS"},
+  {EFI_HII_PACKAGE_END,                 "EFI_HII_PACKAGE_END"},
+  {EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN,   "EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN"},
+  {EFI_HII_PACKAGE_TYPE_SYSTEM_END,     "EFI_HII_PACKAGE_TYPE_SYSTEM_END"},
+};
+
+/**
+  Hii Package type to string.
+
+  @param[in] PackageType    Package Type
+
+  @return Pointer to string.
+
+**/
+CHAR8 *
+HiiPackageTypeToStr (
+  IN UINT8  PackageType
+  )
+{
+  UINTN     Index;
+  for (Index = 0; Index < sizeof (mPackageTypeStringTable) / sizeof 
(mPackageTypeStringTable[0]); Index++) {
+    if (mPackageTypeStringTable[Index].PackageType == PackageType) {
+      return mPackageTypeStringTable[Index].PackageTypeStr;
+    }
+  }
+
+  return "<UnknownPackageType>";
+}
+
+/**
+  Dump Hii Package.
+
+  @param[in] HiiPackage         Pointer to Hii Package.
+
+**/
+VOID
+DumpHiiPackage (
+  IN VOID       *HiiPackage
+  )
+{
+  EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
+  EFI_IFR_OP_HEADER             *IfrOpCodeHeader;
+  EFI_IFR_VARSTORE              *IfrVarStore;
+  EFI_IFR_VARSTORE_EFI          *IfrEfiVarStore;
+
+  HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+  DEBUG ((EFI_D_INFO, "  HiiPackageHeader->Type   - 0x%02x (%a)\n", 
HiiPackageHeader->Type, HiiPackageTypeToStr ((UINT8) HiiPackageHeader->Type)));
+  DEBUG ((EFI_D_INFO, "  HiiPackageHeader->Length - 0x%06x\n", 
HiiPackageHeader->Length));
+
+  switch (HiiPackageHeader->Type) {
+    case EFI_HII_PACKAGE_FORMS:
+      IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+      while ((UINTN) IfrOpCodeHeader < ((UINTN) HiiPackageHeader + 
HiiPackageHeader->Length)) {
+        switch (IfrOpCodeHeader->OpCode) {
+          case EFI_IFR_VARSTORE_OP:
+            IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpCodeHeader;
+            DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", 
IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+            DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->Length - 0x%02x\n", 
IfrOpCodeHeader->Length));
+            DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->Scope  - 0x%02x\n", 
IfrOpCodeHeader->Scope));
+            DEBUG ((EFI_D_INFO, "      Guid       - %g\n", 
&IfrVarStore->Guid));
+            DEBUG ((EFI_D_INFO, "      VarStoreId - 0x%04x\n", 
IfrVarStore->VarStoreId));
+            DEBUG ((EFI_D_INFO, "      Size       - 0x%04x\n", 
IfrVarStore->Size));
+            DEBUG ((EFI_D_INFO, "      Name       - %a\n", IfrVarStore->Name));
+            break;
+
+          case EFI_IFR_VARSTORE_EFI_OP:
+            IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
+            if (IfrEfiVarStore->Header.Length >= sizeof 
(EFI_IFR_VARSTORE_EFI)) {
+              DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->OpCode - 0x%02x 
(%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+              DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->Length - 0x02%x\n", 
IfrOpCodeHeader->Length));
+              DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->Scope  - 0x02%x\n", 
IfrOpCodeHeader->Scope));
+              DEBUG ((EFI_D_INFO, "      Guid       - %g\n", 
&IfrEfiVarStore->Guid));
+              DEBUG ((EFI_D_INFO, "      VarStoreId - 0x%04x\n", 
IfrEfiVarStore->VarStoreId));
+              DEBUG ((EFI_D_INFO, "      Size       - 0x%04x\n", 
IfrEfiVarStore->Size));
+              DEBUG ((EFI_D_INFO, "      Attributes - 0x%08x\n", 
IfrEfiVarStore->Attributes));
+              DEBUG ((EFI_D_INFO, "      Name       - %a\n", 
IfrEfiVarStore->Name));
+            }
+            break;
+
+          case EFI_IFR_ONE_OF_OP:
+          case EFI_IFR_CHECKBOX_OP:
+          case EFI_IFR_NUMERIC_OP:
+          case EFI_IFR_ORDERED_LIST_OP:
+            DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", 
IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+            DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->Length - 0x02%x\n", 
IfrOpCodeHeader->Length));
+            DEBUG ((EFI_D_INFO, "    IfrOpCodeHeader->Scope  - 0x02%x\n", 
IfrOpCodeHeader->Scope));
+            DEBUG ((EFI_D_INFO, "      Prompt       - 0x%04x\n", 
((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt));
+            DEBUG ((EFI_D_INFO, "      Help         - 0x%04x\n", 
((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help));
+            DEBUG ((EFI_D_INFO, "      QuestionId   - 0x%04x\n", 
((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.QuestionId));
+            DEBUG ((EFI_D_INFO, "      VarStoreId   - 0x%04x\n", 
((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId));
+            DEBUG ((EFI_D_INFO, "      VarStoreInfo - 0x%04x\n", 
((EFI_IFR_ONE_OF * )IfrOpCodeHeader)->Question.VarStoreInfo.VarOffset));
+            {
+              EFI_IFR_ONE_OF            *IfrOneOf;
+              EFI_IFR_CHECKBOX          *IfrCheckBox;
+              EFI_IFR_NUMERIC           *IfrNumeric;
+              EFI_IFR_ORDERED_LIST      *IfrOrderedList;
+
+              switch (IfrOpCodeHeader->OpCode) {
+                case EFI_IFR_ONE_OF_OP:
+                  IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
+                  DEBUG ((EFI_D_INFO, "      Flags         - 0x%02x\n", 
IfrOneOf->Flags));
+                  switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
+                  case EFI_IFR_NUMERIC_SIZE_1:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%02x\n", 
IfrOneOf->data.u8.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%02x\n", 
IfrOneOf->data.u8.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%02x\n", 
IfrOneOf->data.u8.Step));
+                    break;
+                  case EFI_IFR_NUMERIC_SIZE_2:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%04x\n", 
IfrOneOf->data.u16.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%04x\n", 
IfrOneOf->data.u16.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%04x\n", 
IfrOneOf->data.u16.Step));
+                    break;
+                  case EFI_IFR_NUMERIC_SIZE_4:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%08x\n", 
IfrOneOf->data.u32.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%08x\n", 
IfrOneOf->data.u32.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%08x\n", 
IfrOneOf->data.u32.Step));
+                    break;
+                  case EFI_IFR_NUMERIC_SIZE_8:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%016lx\n", 
IfrOneOf->data.u64.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%016lx\n", 
IfrOneOf->data.u64.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%016lx\n", 
IfrOneOf->data.u64.Step));
+                    break;
+                  }
+                  break;
+                case EFI_IFR_CHECKBOX_OP:
+                  IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
+                  DEBUG ((EFI_D_INFO, "      Flags         - 0x%02x\n", 
IfrCheckBox->Flags));
+                  break;
+                case EFI_IFR_NUMERIC_OP:
+                  IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
+                  DEBUG ((EFI_D_INFO, "      Flags         - 0x%02x\n", 
IfrNumeric->Flags));
+                  switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
+                  case EFI_IFR_NUMERIC_SIZE_1:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%02x\n", 
IfrNumeric->data.u8.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%02x\n", 
IfrNumeric->data.u8.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%02x\n", 
IfrNumeric->data.u8.Step));
+                    break;
+                  case EFI_IFR_NUMERIC_SIZE_2:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%04x\n", 
IfrNumeric->data.u16.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%04x\n", 
IfrNumeric->data.u16.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%04x\n", 
IfrNumeric->data.u16.Step));
+                    break;
+                  case EFI_IFR_NUMERIC_SIZE_4:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%08x\n", 
IfrNumeric->data.u32.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%08x\n", 
IfrNumeric->data.u32.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%08x\n", 
IfrNumeric->data.u32.Step));
+                    break;
+                  case EFI_IFR_NUMERIC_SIZE_8:
+                    DEBUG ((EFI_D_INFO, "      MinValue      - 0x%016lx\n", 
IfrNumeric->data.u64.MinValue));
+                    DEBUG ((EFI_D_INFO, "      MaxValue      - 0x%016lx\n", 
IfrNumeric->data.u64.MaxValue));
+                    DEBUG ((EFI_D_INFO, "      Step          - 0x%016lx\n", 
IfrNumeric->data.u64.Step));
+                    break;
+                  }
+                  break;
+                case EFI_IFR_ORDERED_LIST_OP:
+                  IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
+                  DEBUG ((EFI_D_INFO, "      MaxContainers - 0x%02x\n", 
IfrOrderedList->MaxContainers));
+                  DEBUG ((EFI_D_INFO, "      Flags         - 0x%02x\n", 
IfrOrderedList->Flags));
+                  break;
+                default:
+                  break;
+              }
+
+              if (IfrOpCodeHeader->Scope != 0) {
+                UINTN                       Scope;
+                EFI_IFR_ONE_OF_OPTION       *IfrOneOfOption;
+
+                IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) 
IfrOpCodeHeader + IfrOpCodeHeader->Length);
+                Scope = 1;
+                while (Scope != 0) {
+                  switch (IfrOpCodeHeader->OpCode) {
+                    case EFI_IFR_ONE_OF_OPTION_OP:
+                      IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION 
*)IfrOpCodeHeader;
+                      DEBUG ((EFI_D_INFO, "!!!!    IfrOpCodeHeader->OpCode - 
0x%02x (%a)\n", (UINTN)IfrOpCodeHeader->OpCode, IfrOpCodeToStr 
(IfrOpCodeHeader->OpCode)));
+                      DEBUG ((EFI_D_INFO, "!!!!    IfrOpCodeHeader->Scope  - 
0x%02x\n", IfrOpCodeHeader->Scope));
+                      DEBUG ((EFI_D_INFO, "!!!!      Option                - 
0x%04x\n", IfrOneOfOption->Option));
+                      DEBUG ((EFI_D_INFO, "!!!!      Flags                 - 
0x%02x\n", IfrOneOfOption->Flags));
+                      DEBUG ((EFI_D_INFO, "!!!!      Type                  - 
0x%02x\n", IfrOneOfOption->Type));
+                      switch (IfrOneOfOption->Type) {
+                        case EFI_IFR_TYPE_NUM_SIZE_8:
+                          DEBUG ((EFI_D_INFO, "!!!!      Value                 
- 0x%02x\n", IfrOneOfOption->Value.u8));
+                          break;
+                        case EFI_IFR_TYPE_NUM_SIZE_16:
+                          DEBUG ((EFI_D_INFO, "!!!!      Value                 
- 0x%04x\n", IfrOneOfOption->Value.u16));
+                          break;
+                        case EFI_IFR_TYPE_NUM_SIZE_32:
+                          DEBUG ((EFI_D_INFO, "!!!!      Value                 
- 0x%08x\n", IfrOneOfOption->Value.u32));
+                          break;
+                        case EFI_IFR_TYPE_NUM_SIZE_64:
+                          DEBUG ((EFI_D_INFO, "!!!!      Value                 
- 0x%016lx\n", IfrOneOfOption->Value.u64));
+                          break;
+                        case EFI_IFR_TYPE_BOOLEAN:
+                          DEBUG ((EFI_D_INFO, "!!!!      Value                 
- 0x%02x\n", IfrOneOfOption->Value.b));
+                          break;
+                        default:
+                          break;
+                      }
+                      break;
+                  }
+
+                  if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
+                    ASSERT (Scope > 0);
+                    Scope--;
+                    if (Scope == 0) {
+                      break;
+                    }
+                  } else if (IfrOpCodeHeader->Scope != 0) {
+                    Scope++;
+                  }
+                  IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) 
IfrOpCodeHeader + IfrOpCodeHeader->Length);
+                }
+              }
+            }
+          default:
+            break;
+        }
+        IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + 
IfrOpCodeHeader->Length);
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+/**
+  Dump Hii Database.
+
+  @param[in] HiiDatabase        Pointer to Hii Database.
+  @param[in] HiiDatabaseSize    Hii Database size.
+
+**/
+VOID
+DumpHiiDatabase (
+  IN VOID       *HiiDatabase,
+  IN UINTN      HiiDatabaseSize
+  )
+{
+  EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageListHeader;
+  EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
+
+  DEBUG ((EFI_D_INFO, "HiiDatabaseSize - 0x%x\n", HiiDatabaseSize));
+  HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
+
+  while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + 
HiiDatabaseSize)) {
+    DEBUG ((EFI_D_INFO, "HiiPackageListHeader->PackageListGuid - %g\n", 
&HiiPackageListHeader->PackageListGuid));
+    DEBUG ((EFI_D_INFO, "HiiPackageListHeader->PackageLength   - 0x%x\n", 
(UINTN)HiiPackageListHeader->PackageLength));
+    HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiPackageListHeader + 1);
+
+    while ((UINTN) HiiPackageHeader < (UINTN) HiiPackageListHeader + 
HiiPackageListHeader->PackageLength) {
+
+      DumpHiiPackage (HiiPackageHeader);
+
+      HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader 
+ HiiPackageHeader->Length);
+    }
+
+    HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) 
HiiPackageListHeader + HiiPackageListHeader->PackageLength);
+  }
+
+  return ;
+}
+#endif
+
+/**
+  Allocates a buffer of a certain pool type.
+
+  Allocates the number bytes specified by AllocationSize of a certain pool 
type and returns a
+  pointer to the allocated buffer.  If AllocationSize is 0, then a valid 
buffer of 0 size is
+  returned.  If there is not enough memory remaining to satisfy the request, 
then NULL is returned.
+
+  @param  MemoryType            The type of memory to allocate.
+  @param  AllocationSize        The number of bytes to allocate.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocatePool (
+  IN EFI_MEMORY_TYPE  MemoryType,
+  IN UINTN            AllocationSize
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Memory;
+
+  Status = gBS->AllocatePool (MemoryType, AllocationSize, &Memory);
+  if (EFI_ERROR (Status)) {
+    Memory = NULL;
+  }
+  return Memory;
+}
+
+/**
+  Allocates and zeros a buffer of type EfiBootServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type 
EfiBootServicesData, clears the
+  buffer with zeros, and returns a pointer to the allocated buffer.  If 
AllocationSize is 0, then a
+  valid buffer of 0 size is returned.  If there is not enough memory remaining 
to satisfy the
+  request, then NULL is returned.
+
+  @param  AllocationSize        The number of bytes to allocate and zero.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocateZeroPool (
+  IN UINTN            AllocationSize
+  )
+{
+  VOID  *Memory;
+
+  Memory = InternalVarCheckAllocatePool (EfiBootServicesData, AllocationSize);
+  if (Memory != NULL) {
+    Memory = ZeroMem (Memory, AllocationSize);
+  }
+  return Memory;
+}
+
+/**
+  Frees a buffer that was previously allocated with one of the pool allocation 
functions in the
+  Memory Allocation Library.
+
+  Frees the buffer specified by Buffer.  Buffer must have been allocated on a 
previous call to the
+  pool allocation services of the Memory Allocation Library.  If it is not 
possible to free pool
+  resources, then this function will perform no actions.
+
+  If Buffer was not allocated with a pool allocation function in the Memory 
Allocation Library,
+  then ASSERT().
+
+  @param  Buffer                The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+InternalVarCheckFreePool (
+  IN VOID   *Buffer
+  )
+{
+  EFI_STATUS    Status;
+
+  Status = gBS->FreePool (Buffer);
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  Reallocates a buffer of type EfiBootServicesData.
+
+  Allocates and zeros the number bytes specified by NewSize from memory of type
+  EfiBootServicesData.  If OldBuffer is not NULL, then the smaller of OldSize 
and
+  NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+  OldBuffer is freed.  A pointer to the newly allocated buffer is returned.
+  If NewSize is 0, then a valid buffer of 0 size is  returned.  If there is not
+  enough memory remaining to satisfy the request, then NULL is returned.
+
+  If the allocation of the new buffer is successful and the smaller of NewSize 
and OldSize
+  is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+  @param  OldSize        The size, in bytes, of OldBuffer.
+  @param  NewSize        The size, in bytes, of the buffer to reallocate.
+  @param  OldBuffer      The buffer to copy to the allocated buffer.  This is 
an optional
+                         parameter that may be NULL.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckReallocatePool (
+  IN UINTN            OldSize,
+  IN UINTN            NewSize,
+  IN VOID             *OldBuffer  OPTIONAL
+  )
+{
+  VOID  *NewBuffer;
+
+  NewBuffer = InternalVarCheckAllocateZeroPool (NewSize);
+  if (NewBuffer != NULL && OldBuffer != NULL) {
+    CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+    InternalVarCheckFreePool (OldBuffer);
+  }
+  return NewBuffer;
+}
+
+/**
+  Merge Hii Question.
+
+  @param[in, out] HiiVariableNode   Pointer to Hii Variable node.
+  @param[in]      HiiQuestion       Pointer to Hii Question.
+  @param[in]      FromFv            Hii Question from FV.
+
+**/
+VOID
+MergeHiiQuestion (
+  IN OUT VAR_CHECK_HII_VARIABLE_NODE    *HiiVariableNode,
+  IN VAR_CHECK_HII_QUESTION_HEADER      *HiiQuestion,
+  IN BOOLEAN                            FromFv
+  )
+{
+  VAR_CHECK_HII_QUESTION_HEADER     *HiiQuestion1;
+  VAR_CHECK_HII_QUESTION_HEADER     *HiiQuestion2;
+  VAR_CHECK_HII_QUESTION_HEADER     *NewHiiQuestion;
+  UINT8                             NewLength;
+  UINT64                            Minimum1;
+  UINT64                            Maximum1;
+  UINT64                            OneValue1;
+  UINT64                            Minimum2;
+  UINT64                            Maximum2;
+  UINT64                            OneValue2;
+  UINT8                             *Ptr;
+  UINT8                             *Ptr1;
+  UINT8                             *Ptr2;
+
+  //
+  // Hii Question from Hii Database has high priority.
+  // Do not to merge Hii Question from Fv to Hii Question from Hii Database.
+  //
+  if (FromFv) {
+    InternalVarCheckFreePool (HiiQuestion);
+    return;
+  }
+
+  HiiQuestion1 = HiiVariableNode->HiiQuestionArray[HiiQuestion->VarOffset];
+  HiiQuestion2 = HiiQuestion;
+
+  ASSERT ((HiiQuestion1->OpCode == HiiQuestion2->OpCode) && 
(HiiQuestion1->StorageWidth == HiiQuestion2->StorageWidth));
+
+  switch (HiiQuestion1->OpCode) {
+    case EFI_IFR_ONE_OF_OP:
+      DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_ONE_OF_OP VarOffset = 
0x%04x\n", HiiQuestion1->VarOffset));
+      //
+      // Get the length of Hii Question 1.
+      //
+      NewLength = HiiQuestion1->Length;
+
+      //
+      // Check if the one of options in Hii Question 2 have been in Hii 
Question 1.
+      //
+      Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
+      while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+        OneValue2 = 0;
+        CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+        Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
+        while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+          OneValue1 = 0;
+          CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+          if (OneValue2 == OneValue1) {
+            //
+            // Match
+            //
+            break;
+          }
+          Ptr1 += HiiQuestion1->StorageWidth;
+        }
+        if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+          //
+          // No match
+          //
+          NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
+        }
+        Ptr2 += HiiQuestion2->StorageWidth;
+      }
+
+      if (NewLength > HiiQuestion1->Length) {
+        //
+        // Merge the one of options of Hii Question 2 and Hii Question 1.
+        //
+        NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
+        ASSERT (NewHiiQuestion != NULL);
+        CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
+        //
+        // Use the new length.
+        //
+        NewHiiQuestion->Length = NewLength;
+        Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
+
+        Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
+        while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+          OneValue2 = 0;
+          CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+          Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
+          while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+            OneValue1 = 0;
+            CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+            if (OneValue2 == OneValue1) {
+              //
+              // Match
+              //
+              break;
+            }
+            Ptr1 += HiiQuestion1->StorageWidth;
+          }
+          if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+            //
+            // No match
+            //
+            CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
+            Ptr += HiiQuestion1->StorageWidth;
+          }
+          Ptr2 += HiiQuestion2->StorageWidth;
+        }
+
+        HiiVariableNode->HiiQuestionArray[HiiQuestion1->VarOffset] = 
NewHiiQuestion;
+        InternalVarCheckFreePool (HiiQuestion1);
+      }
+      break;
+
+    case EFI_IFR_CHECKBOX_OP:
+      DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_CHECKBOX_OP VarOffset = 
0x%04x\n", HiiQuestion1->VarOffset));
+      break;
+
+    case EFI_IFR_NUMERIC_OP:
+      DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_NUMERIC_OP VarOffset = 
0x%04x\n", HiiQuestion1->VarOffset));
+      //
+      // Get minimum and maximum of Hii Question 1.
+      //
+      Minimum1 = 0;
+      Maximum1 = 0;
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
+      CopyMem (&Minimum1, Ptr, HiiQuestion1->StorageWidth);
+      Ptr += HiiQuestion1->StorageWidth;
+      CopyMem (&Maximum1, Ptr, HiiQuestion1->StorageWidth);
+
+      //
+      // Get minimum and maximum of Hii Question 2.
+      //
+      Minimum2 = 0;
+      Maximum2 = 0;
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion2 + 1);
+      CopyMem (&Minimum2, Ptr, HiiQuestion2->StorageWidth);
+      Ptr += HiiQuestion2->StorageWidth;
+      CopyMem (&Maximum2, Ptr, HiiQuestion2->StorageWidth);
+
+      //
+      // Update minimum.
+      //
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
+      if (Minimum2 < Minimum1) {
+        Minimum1 = Minimum2;
+        CopyMem (Ptr, &Minimum1, HiiQuestion1->StorageWidth);
+      }
+      //
+      // Update maximum.
+      //
+      Ptr += HiiQuestion1->StorageWidth;
+      if (Maximum2 > Maximum1) {
+        Maximum1 = Maximum2;
+        CopyMem (Ptr, &Maximum1, HiiQuestion1->StorageWidth);
+      }
+      break;
+
+    case EFI_IFR_ORDERED_LIST_OP:
+      DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_ORDERED_LIST_OP 
VarOffset = 0x%04x\n", HiiQuestion1->VarOffset));
+      //
+      // Get the length of Hii Question 1.
+      //
+      NewLength = HiiQuestion1->Length;
+
+      //
+      // Check if the one of options in Hii Question 2 have been in Hii 
Question 1.
+      //
+      Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 + 
1);
+      while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+        OneValue2 = 0;
+        CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+        Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion1 
+ 1);
+        while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+          OneValue1 = 0;
+          CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+          if (OneValue2 == OneValue1) {
+            //
+            // Match
+            //
+            break;
+          }
+          Ptr1 += HiiQuestion1->StorageWidth;
+        }
+        if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+          //
+          // No match
+          //
+          NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
+        }
+        Ptr2 += HiiQuestion2->StorageWidth;
+      }
+
+      if (NewLength > HiiQuestion1->Length) {
+        //
+        // Merge the one of options of Hii Question 2 and Hii Question 1.
+        //
+        NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
+        ASSERT (NewHiiQuestion != NULL);
+        CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
+        //
+        // Use the new length.
+        //
+        NewHiiQuestion->Length = NewLength;
+        Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
+
+        Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 
+ 1);
+        while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+          OneValue2 = 0;
+          CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+          Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) 
HiiQuestion1 + 1);
+          while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+            OneValue1 = 0;
+            CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+            if (OneValue2 == OneValue1) {
+              //
+              // Match
+              //
+              break;
+            }
+            Ptr1 += HiiQuestion1->StorageWidth;
+          }
+          if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+            //
+            // No match
+            //
+            CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
+            Ptr += HiiQuestion1->StorageWidth;
+          }
+          Ptr2 += HiiQuestion2->StorageWidth;
+        }
+
+        HiiVariableNode->HiiQuestionArray[HiiQuestion1->VarOffset] = 
NewHiiQuestion;
+        InternalVarCheckFreePool (HiiQuestion1);
+      }
+      break;
+
+    default:
+      ASSERT (FALSE);
+      return;
+      break;
+  }
+
+  //
+  //
+  // Hii Question 2 has been merged with Hii Question 1.
+  //
+  InternalVarCheckFreePool (HiiQuestion2);
+}
+
+/**
+  Get OneOf option data.
+
+  @param[in]  IfrOpCodeHeader   Pointer to Ifr OpCode header.
+  @param[out] Count             Pointer to option count.
+  @param[out] Width             Pointer to option width.
+  @param[out] OptionBuffer      Pointer to option buffer.
+
+**/
+VOID
+GetOneOfOption (
+  IN  EFI_IFR_OP_HEADER     *IfrOpCodeHeader,
+  OUT UINTN                 *Count,
+  OUT UINT8                 *Width,
+  OUT VOID                  *OptionBuffer OPTIONAL
+  )
+{
+  UINTN                     Scope;
+  EFI_IFR_ONE_OF_OPTION     *IfrOneOfOption;
+
+  //
+  // Assume all OPTION has same Width.
+  //
+  *Count = 0;
+
+  if (IfrOpCodeHeader->Scope != 0) {
+    //
+    // Nested OpCode.
+    //
+    Scope = 1;
+    IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + 
IfrOpCodeHeader->Length);
+    while (Scope != 0) {
+      switch (IfrOpCodeHeader->OpCode) {
+        case EFI_IFR_ONE_OF_OPTION_OP:
+          IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpCodeHeader;
+          switch (IfrOneOfOption->Type) {
+            case EFI_IFR_TYPE_NUM_SIZE_8:
+              *Count = *Count + 1;
+              *Width = sizeof (UINT8);
+              if (OptionBuffer != NULL) {
+                CopyMem (OptionBuffer, &IfrOneOfOption->Value.u8, sizeof 
(UINT8));
+                OptionBuffer = (UINT8 *) OptionBuffer + 1;
+              }
+              break;
+            case EFI_IFR_TYPE_NUM_SIZE_16:
+              *Count = *Count + 1;
+              *Width = sizeof (UINT16);
+              if (OptionBuffer != NULL) {
+                CopyMem (OptionBuffer, &IfrOneOfOption->Value.u16, sizeof 
(UINT16));
+                OptionBuffer = (UINT16 *) OptionBuffer + 1;
+              }
+              break;
+            case EFI_IFR_TYPE_NUM_SIZE_32:
+              *Count = *Count + 1;
+              *Width = sizeof (UINT32);
+              if (OptionBuffer != NULL) {
+                CopyMem (OptionBuffer, &IfrOneOfOption->Value.u32, sizeof 
(UINT32));
+                OptionBuffer = (UINT32 *) OptionBuffer + 1;
+              }
+              break;
+            case EFI_IFR_TYPE_NUM_SIZE_64:
+              *Count = *Count + 1;
+              *Width = sizeof (UINT64);
+              if (OptionBuffer != NULL) {
+                CopyMem (OptionBuffer, &IfrOneOfOption->Value.u64, sizeof 
(UINT64));
+                OptionBuffer = (UINT64 *) OptionBuffer + 1;
+              }
+              break;
+            case EFI_IFR_TYPE_BOOLEAN:
+              *Count = *Count + 1;
+              *Width = sizeof (BOOLEAN);
+              if (OptionBuffer != NULL) {
+                CopyMem (OptionBuffer, &IfrOneOfOption->Value.b, sizeof 
(BOOLEAN));
+                OptionBuffer = (BOOLEAN *) OptionBuffer + 1;
+              }
+              break;
+            default:
+              break;
+          }
+          break;
+      }
+
+      //
+      // Until End OpCode.
+      //
+      if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
+        ASSERT (Scope > 0);
+        Scope--;
+        if (Scope == 0) {
+          break;
+        }
+      } else if (IfrOpCodeHeader->Scope != 0) {
+        //
+        // Nested OpCode.
+        //
+        Scope++;
+      }
+      IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + 
IfrOpCodeHeader->Length);
+    }
+  }
+
+  return ;
+}
+
+/**
+  Parse Hii Question Oneof.
+
+  @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
+
+  return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionOneOf (
+  IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader
+  )
+{
+  EFI_IFR_ONE_OF                *IfrOneOf;
+  VAR_CHECK_HII_QUESTION_ONEOF  *OneOf;
+  UINTN                         Length;
+  UINT8                         Width;
+  UINTN                         OptionCount;
+  UINT8                         OptionWidth;
+
+  IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
+
+  Width = (UINT8) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
+
+  GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
+  ASSERT (Width == OptionWidth);
+
+  Length = sizeof (*OneOf) + OptionCount * Width;
+
+  OneOf = InternalVarCheckAllocateZeroPool (Length);
+  ASSERT (OneOf != NULL);
+  OneOf->OpCode       = EFI_IFR_ONE_OF_OP;
+  OneOf->Length       = (UINT8) Length;
+  OneOf->VarOffset    = IfrOneOf->Question.VarStoreInfo.VarOffset;
+  OneOf->StorageWidth = Width;
+
+  GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OneOf + 1);
+
+  return (VAR_CHECK_HII_QUESTION_HEADER *) OneOf;
+}
+
+/**
+  Parse Hii Question CheckBox.
+
+  @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
+
+  return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionCheckBox (
+  IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader
+  )
+{
+  EFI_IFR_CHECKBOX                  *IfrCheckBox;
+  VAR_CHECK_HII_QUESTION_CHECKBOX   *CheckBox;
+
+  IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
+
+  CheckBox = InternalVarCheckAllocateZeroPool (sizeof (*CheckBox));
+  ASSERT (CheckBox != NULL);
+  CheckBox->OpCode       = EFI_IFR_CHECKBOX_OP;
+  CheckBox->Length       = (UINT8) sizeof (*CheckBox);;
+  CheckBox->VarOffset    = IfrCheckBox->Question.VarStoreInfo.VarOffset;
+  CheckBox->StorageWidth = (UINT8) sizeof (BOOLEAN);
+
+  return (VAR_CHECK_HII_QUESTION_HEADER *) CheckBox;
+}
+
+/**
+  Parse Hii Question Numeric.
+
+  @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
+
+  return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionNumeric (
+  IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader
+  )
+{
+  EFI_IFR_NUMERIC                   *IfrNumeric;
+  VAR_CHECK_HII_QUESTION_NUMERIC    *Numeric;
+  UINT8                             Width;
+
+  IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
+
+  Numeric = InternalVarCheckAllocateZeroPool (sizeof 
(VAR_CHECK_HII_QUESTION_NUMERIC) + 2 * sizeof (UINT64));
+  ASSERT (Numeric != NULL);
+
+  Width = (UINT8) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
+
+  Numeric->OpCode       = EFI_IFR_NUMERIC_OP;
+  Numeric->Length       = (UINT8) (sizeof (VAR_CHECK_HII_QUESTION_NUMERIC) + 2 
* Width);
+  Numeric->VarOffset    = IfrNumeric->Question.VarStoreInfo.VarOffset;
+  Numeric->StorageWidth = Width;
+
+  CopyMem (Numeric + 1, &IfrNumeric->data, Width * 2);
+
+  return (VAR_CHECK_HII_QUESTION_HEADER *) Numeric;
+}
+
+/**
+  Parse Hii Question OrderedList.
+
+  @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
+
+  return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionOrderedList (
+  IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader
+  )
+{
+  EFI_IFR_ORDERED_LIST                  *IfrOrderedList;
+  VAR_CHECK_HII_QUESTION_ORDEREDLIST    *OrderedList;
+  UINTN                                 Length;
+  UINTN                                 OptionCount;
+  UINT8                                 OptionWidth;
+
+  IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
+
+  GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
+
+  Length = sizeof (*OrderedList) + OptionCount * OptionWidth;
+
+  OrderedList = InternalVarCheckAllocateZeroPool (Length);
+  ASSERT (OrderedList != NULL);
+  OrderedList->OpCode        = EFI_IFR_ORDERED_LIST_OP;
+  OrderedList->Length        = (UINT8) Length;
+  OrderedList->VarOffset     = IfrOrderedList->Question.VarStoreInfo.VarOffset;
+  OrderedList->StorageWidth  = OptionWidth;
+  OrderedList->MaxContainers = IfrOrderedList->MaxContainers;
+
+  GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OrderedList + 
1);
+
+  return (VAR_CHECK_HII_QUESTION_HEADER *) OrderedList;
+}
+
+/**
+  Parse and create Hii Question node.
+
+  @param[in] HiiVariableNode    Pointer to Hii Variable node.
+  @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
+  @param[in] FromFv             Hii Question from FV.
+
+**/
+VOID
+ParseHiiQuestion (
+  IN VAR_CHECK_HII_VARIABLE_NODE    *HiiVariableNode,
+  IN  EFI_IFR_OP_HEADER             *IfrOpCodeHeader,
+  IN BOOLEAN                        FromFv
+  )
+{
+  VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+  switch (IfrOpCodeHeader->OpCode) {
+    case EFI_IFR_ONE_OF_OP:
+      HiiQuestion = ParseHiiQuestionOneOf (IfrOpCodeHeader);
+      break;
+
+    case EFI_IFR_CHECKBOX_OP:
+      HiiQuestion = ParseHiiQuestionCheckBox (IfrOpCodeHeader);
+      break;
+
+    case EFI_IFR_NUMERIC_OP:
+      HiiQuestion = ParseHiiQuestionNumeric (IfrOpCodeHeader);
+      break;
+
+    case EFI_IFR_ORDERED_LIST_OP:
+      HiiQuestion = ParseHiiQuestionOrderedList (IfrOpCodeHeader);
+      break;
+
+    default:
+      ASSERT (FALSE);
+      return;
+      break;
+  }
+
+  if (HiiVariableNode->HiiQuestionArray[HiiQuestion->VarOffset] != NULL) {
+    MergeHiiQuestion (HiiVariableNode, HiiQuestion, FromFv);
+  } else {
+    HiiVariableNode->HiiQuestionArray[HiiQuestion->VarOffset] = HiiQuestion;
+  }
+}
+
+/**
+  Find Hii variable node by name and GUID.
+
+  @param[in] Name   Pointer to variable name.
+  @param[in] Guid   Pointer to vendor GUID.
+
+  @return Pointer to Hii Variable node.
+
+**/
+VAR_CHECK_HII_VARIABLE_NODE *
+FindHiiVariableNode (
+  IN CHAR16     *Name,
+  IN EFI_GUID   *Guid
+  )
+{
+  VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
+  LIST_ENTRY                    *Link;
+
+  for (Link = mVarCheckHiiList.ForwardLink
+      ;Link != &mVarCheckHiiList
+      ;Link = Link->ForwardLink) {
+    HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+
+    if ((StrCmp (Name, (CHAR16 *) (HiiVariableNode->HiiVariable + 1)) == 0) &&
+        CompareGuid (Guid, &HiiVariableNode->HiiVariable->Guid)) {
+      return HiiVariableNode;
+    }
+  }
+
+  return NULL;
+}
+
+/**
+  Find Hii variable node by var store id.
+
+  @param[in] VarStoreId         Var store id.
+
+  @return Pointer to Hii Variable node.
+
+**/
+VAR_CHECK_HII_VARIABLE_NODE *
+FindHiiVariableNodeByVarStoreId (
+  IN EFI_VARSTORE_ID            VarStoreId
+  )
+{
+  VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
+  LIST_ENTRY                    *Link;
+
+  if (VarStoreId == 0) {
+    //
+    // The variable store identifier, which is unique within the current form 
set.
+    // A value of zero is invalid.
+    //
+    return NULL;
+  }
+
+  for (Link = mVarCheckHiiList.ForwardLink
+      ;Link != &mVarCheckHiiList
+      ;Link = Link->ForwardLink) {
+    HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+    //
+    // The variable store identifier, which is unique within the current form 
set.
+    //
+    if (VarStoreId == HiiVariableNode->VarStoreId) {
+      return HiiVariableNode;
+    }
+  }
+
+  return NULL;
+}
+
+/**
+  Destroy var store id in the Hii Variable node after parsing one Hii Package.
+
+**/
+VOID
+DestroyVarStoreId (
+  VOID
+  )
+{
+  VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
+  LIST_ENTRY                    *Link;
+
+  for (Link = mVarCheckHiiList.ForwardLink
+      ;Link != &mVarCheckHiiList
+      ;Link = Link->ForwardLink) {
+    HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+    //
+    // The variable store identifier, which is unique within the current form 
set.
+    // A value of zero is invalid.
+    //
+    HiiVariableNode->VarStoreId = 0;
+  }
+}
+
+/**
+  Create Hii Variable node.
+
+  @param[in] IfrEfiVarStore  Pointer to EFI VARSTORE.
+
+**/
+VOID
+CreateHiiVariableNode (
+  IN EFI_IFR_VARSTORE_EFI   *IfrEfiVarStore
+  )
+{
+  VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
+  VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+  UINTN                         HeaderLength;
+  CHAR16                        *VarName;
+  UINTN                         VarNameSize;
+
+  //
+  // Get variable name.
+  //
+  VarNameSize = AsciiStrSize ((CHAR8 *) IfrEfiVarStore->Name) * 2;
+  if (VarNameSize > mMaxVarNameSize) {
+    mVarName = InternalVarCheckReallocatePool (mMaxVarNameSize, VarNameSize, 
mVarName);
+    ASSERT (mVarName != NULL);
+    mMaxVarNameSize = VarNameSize;
+  }
+  AsciiStrToUnicodeStr ((CHAR8 *) IfrEfiVarStore->Name, mVarName);
+  VarName = mVarName;
+
+  HiiVariableNode = FindHiiVariableNode (
+                      VarName,
+                      &IfrEfiVarStore->Guid
+                      );
+  if (HiiVariableNode == NULL) {
+    //
+    // Not found, then create new.
+    //
+    HeaderLength = sizeof (*HiiVariable) + VarNameSize;
+    HiiVariable = InternalVarCheckAllocateZeroPool (HeaderLength);
+    ASSERT (HiiVariable != NULL);
+    HiiVariable->Revision = VAR_CHECK_HII_REVISION;
+    HiiVariable->OpCode = EFI_IFR_VARSTORE_EFI_OP;
+    HiiVariable->HeaderLength = (UINT16) HeaderLength;
+    HiiVariable->Size = IfrEfiVarStore->Size;
+    HiiVariable->Attributes = IfrEfiVarStore->Attributes;
+    CopyGuid (&HiiVariable->Guid, &IfrEfiVarStore->Guid);
+    StrCpyS ((CHAR16 *) (HiiVariable + 1), VarNameSize / sizeof (CHAR16), 
VarName);
+
+    HiiVariableNode = InternalVarCheckAllocateZeroPool (sizeof 
(*HiiVariableNode));
+    ASSERT (HiiVariableNode != NULL);
+    HiiVariableNode->Signature = VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE;
+    HiiVariableNode->HiiVariable = HiiVariable;
+    //
+    // The variable store identifier, which is unique within the current form 
set.
+    //
+    HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
+    HiiVariableNode->HiiQuestionArray = InternalVarCheckAllocateZeroPool 
(IfrEfiVarStore->Size * sizeof (VAR_CHECK_HII_QUESTION_HEADER *));
+
+    InsertTailList (&mVarCheckHiiList, &HiiVariableNode->Link);
+  } else {
+    HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
+  }
+}
+
+/**
+  Parse and create Hii Variable node list.
+
+  @param[in] HiiPackage         Pointer to Hii Package.
+
+**/
+VOID
+ParseHiiVariable (
+  IN VOID       *HiiPackage
+  )
+{
+  EFI_HII_PACKAGE_HEADER    *HiiPackageHeader;
+  EFI_IFR_OP_HEADER         *IfrOpCodeHeader;
+  EFI_IFR_VARSTORE_EFI      *IfrEfiVarStore;
+
+  HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+  switch (HiiPackageHeader->Type) {
+    case EFI_HII_PACKAGE_FORMS:
+      IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+      while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + 
HiiPackageHeader->Length) {
+        switch (IfrOpCodeHeader->OpCode) {
+          case EFI_IFR_VARSTORE_EFI_OP:
+            //
+            // Come to EFI VARSTORE in Form Package.
+            //
+            IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
+            if ((IfrEfiVarStore->Header.Length >= sizeof 
(EFI_IFR_VARSTORE_EFI)) &&
+                ((IfrEfiVarStore->Attributes & EFI_VARIABLE_NON_VOLATILE) != 
0)) {
+              //
+              // Only create node list for Hii Variable with NV attribute.
+              //
+              CreateHiiVariableNode (IfrEfiVarStore);
+            }
+            break;
+
+          default:
+            break;
+        }
+      IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + 
IfrOpCodeHeader->Length);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+/**
+  Var Check Parse Hii Package.
+
+  @param[in] HiiPackage         Pointer to Hii Package.
+  @param[in] FromFv             Hii Package from FV.
+
+**/
+VOID
+VarCheckParseHiiPackage (
+  IN VOID       *HiiPackage,
+  IN BOOLEAN    FromFv
+  )
+{
+  EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
+  EFI_IFR_OP_HEADER             *IfrOpCodeHeader;
+  VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
+
+  //
+  // Parse and create Hii Variable node list for this Hii Package.
+  //
+  ParseHiiVariable (HiiPackage);
+
+  HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+  switch (HiiPackageHeader->Type) {
+    case EFI_HII_PACKAGE_FORMS:
+      IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+      while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + 
HiiPackageHeader->Length) {
+        switch (IfrOpCodeHeader->OpCode) {
+          case EFI_IFR_ONE_OF_OP:
+          case EFI_IFR_CHECKBOX_OP:
+          case EFI_IFR_NUMERIC_OP:
+          case EFI_IFR_ORDERED_LIST_OP:
+            HiiVariableNode = FindHiiVariableNodeByVarStoreId 
(((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId);
+            if ((HiiVariableNode == NULL) ||
+                //
+                // No related Hii Variable node found.
+                //
+                ((((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt 
== 0) && (((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help == 0))) {
+                //
+                // meanless IFR item introduced by ECP.
+                //
+            } else {
+              //
+              // Normal IFR
+              //
+              ParseHiiQuestion (HiiVariableNode, IfrOpCodeHeader, FromFv);
+            }
+          default:
+            break;
+        }
+        IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + 
IfrOpCodeHeader->Length);
+      }
+      break;
+
+    default:
+      break;
+  }
+  DestroyVarStoreId ();
+}
+
+/**
+  Var Check Parse Hii Database.
+
+  @param[in] HiiDatabase        Pointer to Hii Database.
+  @param[in] HiiDatabaseSize    Hii Database size.
+
+**/
+VOID
+VarCheckParseHiiDatabase (
+  IN VOID       *HiiDatabase,
+  IN UINTN      HiiDatabaseSize
+  )
+{
+  EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageListHeader;
+  EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
+
+  HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
+
+  while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + 
HiiDatabaseSize)) {
+    HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiPackageListHeader + 1);
+
+    while ((UINTN) HiiPackageHeader < ((UINTN) HiiPackageListHeader + 
HiiPackageListHeader->PackageLength)) {
+      //
+      // Parse Hii Pacakge.
+      //
+      VarCheckParseHiiPackage (HiiPackageHeader, FALSE);
+
+      HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader 
+ HiiPackageHeader->Length);
+    }
+
+    HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) 
HiiPackageListHeader + HiiPackageListHeader->PackageLength);
+  }
+}
+
+/**
+  Destroy Hii Variable node.
+
+**/
+VOID
+DestroyHiiVariableNode (
+  VOID
+  )
+{
+  VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
+  LIST_ENTRY                    *HiiVariableLink;
+  UINTN                         Index;
+
+  while (mVarCheckHiiList.ForwardLink != &mVarCheckHiiList) {
+    HiiVariableLink = mVarCheckHiiList.ForwardLink;
+    HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+
+    RemoveEntryList (&HiiVariableNode->Link);
+
+    //
+    // Free the allocated buffer.
+    //
+    for (Index = 0; Index < HiiVariableNode->HiiVariable->Size; Index++) {
+      if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+        InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray[Index]);
+      }
+    }
+    InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray);
+    InternalVarCheckFreePool (HiiVariableNode->HiiVariable);
+    InternalVarCheckFreePool (HiiVariableNode);
+  }
+}
+
+/**
+  Build VarCheckHiiBin.
+
+  @param[out] Size      Pointer to VarCheckHii size.
+
+  @return Pointer to VarCheckHiiBin.
+
+**/
+VOID *
+BuildVarCheckHiiBin (
+  OUT UINTN  *Size
+  )
+{
+  VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
+  LIST_ENTRY                    *HiiVariableLink;
+  UINTN                         Index;
+  VOID                          *Data;
+  UINT8                         *Ptr;
+  UINT32                        BinSize;
+  UINT32                        HiiVariableLength;
+
+  //
+  // Get Size
+  //
+  BinSize = 0;
+
+  for (HiiVariableLink = mVarCheckHiiList.ForwardLink
+      ;HiiVariableLink != &mVarCheckHiiList
+      ;HiiVariableLink = HiiVariableLink->ForwardLink) {
+    //
+    // For Hii Variable header align.
+    //
+    BinSize = (UINT32) HEADER_ALIGN (BinSize);
+
+    HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+    HiiVariableLength = HiiVariableNode->HiiVariable->HeaderLength;
+
+    for (Index = 0; Index < HiiVariableNode->HiiVariable->Size; Index++) {
+      if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+        //
+        // For Hii Question header align.
+        //
+        HiiVariableLength = (UINT32) HEADER_ALIGN (HiiVariableLength);
+        HiiVariableLength += HiiVariableNode->HiiQuestionArray[Index]->Length;
+      }
+    }
+
+    HiiVariableNode->HiiVariable->Length = HiiVariableLength;
+    BinSize += HiiVariableLength;
+  }
+
+  DEBUG ((EFI_D_INFO, "VarCheckHiiBin - size = 0x%x\n", BinSize));
+  if (BinSize == 0) {
+    *Size = BinSize;
+    return NULL;
+  }
+
+  //
+  // AllocatePages () and AllocatePool () from gBS are used for the process of 
VarCheckHiiBin generation.
+  // Only here AllocateRuntimeZeroPool () from MemoryAllocateLib is used for 
runtime access
+  // in SetVariable check handler.
+  //
+  Data = AllocateRuntimeZeroPool (BinSize);
+  ASSERT (Data != NULL);
+  DEBUG ((EFI_D_INFO, "VarCheckHiiBin - built at 0x%x\n", Data));
+
+  //
+  // Gen Data
+  //
+  Ptr = Data;
+  for (HiiVariableLink = mVarCheckHiiList.ForwardLink
+      ;HiiVariableLink != &mVarCheckHiiList
+      ;HiiVariableLink = HiiVariableLink->ForwardLink) {
+    //
+    // For Hii Variable header align.
+    //
+    Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
+
+    HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+    CopyMem (Ptr, HiiVariableNode->HiiVariable, 
HiiVariableNode->HiiVariable->HeaderLength);
+    Ptr += HiiVariableNode->HiiVariable->HeaderLength;
+
+    for (Index = 0; Index < HiiVariableNode->HiiVariable->Size; Index++) {
+      if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+        //
+        // For Hii Question header align.
+        //
+        Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
+        CopyMem (Ptr, HiiVariableNode->HiiQuestionArray[Index], 
HiiVariableNode->HiiQuestionArray[Index]->Length);
+        Ptr += HiiVariableNode->HiiQuestionArray[Index]->Length;
+      }
+    }
+  }
+
+  *Size = BinSize;
+  return Data;
+}
+
+/**
+  Generate VarCheckHiiBin from Hii Database and FV.
+
+**/
+VOID
+EFIAPI
+VarCheckHiiGen (
+  VOID
+  )
+{
+  VarCheckHiiGenFromHiiDatabase ();
+  VarCheckHiiGenFromFv ();
+
+  mVarCheckHiiBin = BuildVarCheckHiiBin (&mVarCheckHiiBinSize);
+  if (mVarCheckHiiBin == NULL) {
+    DEBUG ((EFI_D_INFO, "[VarCheckHii] This driver could be removed from *.dsc 
and *.fdf\n"));
+    return;
+  }
+
+  DestroyHiiVariableNode ();
+  if (mVarName != NULL) {
+    InternalVarCheckFreePool (mVarName);
+  }
+
+#ifdef DUMP_VAR_CHECK_HII
+  DEBUG_CODE (
+    DumpVarCheckHii (mVarCheckHiiBin, mVarCheckHiiBinSize);
+  );
+#endif
+}
+
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
new file mode 100644
index 0000000..f81be2e
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
@@ -0,0 +1,136 @@
+/** @file
+  Include file for Var Check Hii bin generation.
+
+Copyright (c) 2015, 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.
+
+**/
+
+#ifndef _VAR_CHECK_HII_GEN_H_
+#define _VAR_CHECK_HII_GEN_H_
+
+#include "VarCheckHii.h"
+
+/**
+  Dump Hii Package.
+
+  @param[in] HiiPackage         Pointer to Hii Package.
+
+**/
+VOID
+DumpHiiPackage (
+  IN VOID       *HiiPackage
+  );
+
+/**
+  Dump Hii Database.
+
+  @param[in] HiiDatabase        Pointer to Hii Database.
+  @param[in] HiiDatabaseSize    Hii Database size.
+
+**/
+VOID
+DumpHiiDatabase (
+  IN VOID       *HiiDatabase,
+  IN UINTN      HiiDatabaseSize
+  );
+
+/**
+  Allocates and zeros a buffer of type EfiBootServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type 
EfiBootServicesData, clears the
+  buffer with zeros, and returns a pointer to the allocated buffer.  If 
AllocationSize is 0, then a
+  valid buffer of 0 size is returned.  If there is not enough memory remaining 
to satisfy the
+  request, then NULL is returned.
+
+  @param  AllocationSize        The number of bytes to allocate and zero.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocateZeroPool (
+  IN UINTN            AllocationSize
+  );
+
+/**
+  Frees a buffer that was previously allocated with one of the pool allocation 
functions in the
+  Memory Allocation Library.
+
+  Frees the buffer specified by Buffer.  Buffer must have been allocated on a 
previous call to the
+  pool allocation services of the Memory Allocation Library.  If it is not 
possible to free pool
+  resources, then this function will perform no actions.
+
+  If Buffer was not allocated with a pool allocation function in the Memory 
Allocation Library,
+  then ASSERT().
+
+  @param  Buffer                The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+InternalVarCheckFreePool (
+  IN VOID   *Buffer
+  );
+
+/**
+  Var Check Parse Hii Package.
+
+  @param[in] HiiPackage         Pointer to Hii Package.
+  @param[in] FromFv             Hii Package from FV.
+
+**/
+VOID
+VarCheckParseHiiPackage (
+  IN VOID       *HiiPackage,
+  IN BOOLEAN    FromFv
+  );
+
+/**
+  Var Check Parse Hii Database.
+
+  @param[in] HiiDatabase        Pointer to Hii Database.
+  @param[in] HiiDatabaseSize    Hii Database size.
+
+**/
+VOID
+VarCheckParseHiiDatabase (
+  IN VOID       *HiiDatabase,
+  IN UINTN      HiiDatabaseSize
+  );
+
+/**
+  Generate from FV.
+
+**/
+VOID
+VarCheckHiiGenFromFv (
+  VOID
+  );
+
+/**
+  Generate from Hii Database.
+
+**/
+VOID
+VarCheckHiiGenFromHiiDatabase (
+  VOID
+  );
+
+/**
+  Generate VarCheckHiiBin from Hii Database and FV.
+
+**/
+VOID
+EFIAPI
+VarCheckHiiGen (
+  VOID
+  );
+
+#endif
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
new file mode 100644
index 0000000..21fc80e
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
@@ -0,0 +1,443 @@
+/** @file
+  Var Check Hii generation from FV.
+
+Copyright (c) 2015, 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 "VarCheckHiiGen.h"
+
+// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
+#define EFI_VFR_ATTRACT_GUID \
+{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } 
}
+
+EFI_GUID  gVfrArrayAttractGuid  = EFI_VFR_ATTRACT_GUID;
+
+#define ALL_FF_GUID \
+{ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 
} }
+
+EFI_GUID mAllFfGuid             = ALL_FF_GUID;
+
+#define VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE     SIGNATURE_32 ('V', 'D', 'R', 
'I')
+
+typedef struct {
+  UINTN             Signature;
+  LIST_ENTRY        Link;
+  EFI_GUID          *DriverGuid;
+} VAR_CHECK_VFR_DRIVER_INFO;
+
+LIST_ENTRY                      mVfrDriverList = INITIALIZE_LIST_HEAD_VARIABLE 
(mVfrDriverList);
+
+#define VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK(a)  CR (a, 
VAR_CHECK_VFR_DRIVER_INFO, Link, VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE)
+
+#define MAX_MATCH_GUID_NUM      100
+
+/**
+  Get the address by Guid.
+
+  Parse the FFS and find the GUID address.
+  There may be multiple Guids matching the searched Guid.
+
+  @param Ffs                Pointer to the FFS.
+  @param Guid               Guid to find.
+  @param Length             The length of FFS.
+  @param Offset             Pointer to pointer to the offset.
+  @param NumOfMatchingGuid  The number of matching Guid.
+
+  @retval EFI_SUCCESS       One or multiple Guids matching the searched Guid.
+  @retval EFI_NOT_FOUND     No Guid matching the searched Guid.
+
+**/
+EFI_STATUS
+GetAddressByGuid (
+  IN  VOID          *Ffs,
+  IN  EFI_GUID      *Guid,
+  IN  UINTN         Length,
+  OUT UINTN         **Offset,
+  OUT UINT8         *NumOfMatchingGuid
+  )
+{
+  UINTN     LoopControl;
+  BOOLEAN   Found;
+
+  if((Ffs == NULL) || (Guid == NULL) || (Length == 0)){
+    return EFI_NOT_FOUND;
+  }
+
+  if (NumOfMatchingGuid != NULL) {
+    *NumOfMatchingGuid = 0;
+  }
+
+  Found = FALSE;
+  for (LoopControl = 0; LoopControl < Length; LoopControl++) {
+    if (CompareGuid (Guid, (EFI_GUID *) ((UINT8 *) Ffs + LoopControl))) {
+      Found = TRUE;
+      //
+      // If NumOfMatchGuid or Offset are NULL, means user only want
+      // to check whether current FFS includes this Guid or not.
+      //
+      if ((NumOfMatchingGuid != NULL) && (Offset != NULL)) {
+        if (*NumOfMatchingGuid == 0) {
+          *Offset = InternalVarCheckAllocateZeroPool (sizeof (UINTN) * 
MAX_MATCH_GUID_NUM);
+          ASSERT (*Offset != NULL);
+        }
+        *(*Offset + *NumOfMatchingGuid) = LoopControl + sizeof (EFI_GUID);
+        (*NumOfMatchingGuid)++;
+      } else {
+        break;
+      }
+    }
+  }
+
+  return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
+}
+
+/**
+  Search the VfrBin Base address.
+
+  According to the known GUID gVfrArrayAttractGuid to get the base address 
from FFS.
+
+  @param Ffs                    Pointer to the FFS.
+  @param EfiAddr                Pointer to the EFI in FFS
+  @param Length                 The length of FFS.
+  @param Offset                 Pointer to pointer to the Addr (Offset).
+  @param NumOfMatchingOffset    The number of Addr (Offset).
+
+  @retval EFI_SUCCESS           Get the address successfully.
+  @retval EFI_NOT_FOUND         No VfrBin found.
+
+**/
+EFI_STATUS
+SearchVfrBinInFfs (
+   IN  VOID      *Ffs,
+   IN  VOID      *EfiAddr,
+   IN  UINTN     Length,
+   OUT UINTN     **Offset,
+   OUT UINT8     *NumOfMatchingOffset
+  )
+{
+  UINTN        Index;
+  EFI_STATUS   Status;
+  UINTN        VirOffValue;
+
+  if ((Ffs == NULL) || (Offset == NULL)) {
+    return EFI_NOT_FOUND;
+  }
+  Status = GetAddressByGuid (
+             Ffs,
+             &gVfrArrayAttractGuid,
+             Length,
+             Offset,
+             NumOfMatchingOffset
+             );
+  if (Status != EFI_SUCCESS) {
+    return Status;
+  }
+
+  for (Index = 0; Index < *NumOfMatchingOffset; Index++) {
+    //
+    // Got the virOffset after the GUID
+    //
+    VirOffValue = *(UINTN *) ((UINTN) Ffs + *(*Offset + Index));
+    //
+    // Transfer the offset to the VA address. One modules may own multiple 
VfrBin address.
+    //
+    *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
+  }
+
+  return Status;
+}
+
+/**
+  Parse FFS.
+
+  @param[in] Fv2            Pointer to Fv2 protocol.
+  @param[in] DriverGuid     Pointer to driver GUID.
+
+  @return Found the driver in the FV or not.
+
+**/
+BOOLEAN
+ParseFfs (
+  IN EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv2,
+  IN EFI_GUID                       *DriverGuid
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_FV_FILETYPE               FoundType;
+  EFI_FV_FILE_ATTRIBUTES        FileAttributes;
+  UINT32                        AuthenticationStatus;
+  UINTN                         Size;
+  VOID                          *Buffer;
+  UINTN                         SectionSize;
+  VOID                          *SectionBuffer;
+  UINTN                         VfrBinIndex;
+  UINT8                         NumberofMatchingVfrBin;
+  UINTN                         *VfrBinBaseAddress;
+
+  Status = Fv2->ReadFile (
+                  Fv2,
+                  DriverGuid,
+                  NULL,
+                  &Size,
+                  &FoundType,
+                  &FileAttributes,
+                  &AuthenticationStatus
+                  );
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  Buffer = NULL;
+  Status = Fv2->ReadSection (
+                  Fv2,
+                  DriverGuid,
+                  EFI_SECTION_RAW,
+                  0, // Instance
+                  &Buffer,
+                  &Size,
+                  &AuthenticationStatus
+                  );
+   if (!EFI_ERROR (Status)) {
+     Status = SearchVfrBinInFfs (Buffer, 0, Size, &VfrBinBaseAddress, 
&NumberofMatchingVfrBin);
+     if (!EFI_ERROR (Status)) {
+        SectionBuffer = NULL;
+        Status = Fv2->ReadSection (
+                        Fv2,
+                        DriverGuid,
+                        EFI_SECTION_PE32,
+                        0, // Instance
+                        &SectionBuffer,
+                        &SectionSize,
+                        &AuthenticationStatus
+                        );
+        if (!EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_INFO, "FfsNameGuid - %g\n", DriverGuid));
+          DEBUG ((EFI_D_INFO, "NumberofMatchingVfrBin - 0x%02x\n", 
NumberofMatchingVfrBin));
+
+          for (VfrBinIndex = 0; VfrBinIndex < NumberofMatchingVfrBin; 
VfrBinIndex++) {
+#ifdef DUMP_HII_DATA
+            DEBUG_CODE (
+              DumpHiiPackage ((UINT8 *) (UINTN) SectionBuffer + 
VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32));
+              );
+#endif
+            VarCheckParseHiiPackage ((UINT8 *) (UINTN) SectionBuffer + 
VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32), TRUE);
+          }
+
+          FreePool (SectionBuffer);
+        }
+
+        InternalVarCheckFreePool (VfrBinBaseAddress);
+      }
+
+      FreePool (Buffer);
+    }
+
+   return TRUE;
+}
+
+/**
+  Parse FVs.
+
+  @param[in] ScanAll    Scan all modules in all FVs or not.
+
+**/
+VOID
+ParseFv (
+  IN BOOLEAN    ScanAll
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_HANDLE                    *HandleBuffer;
+  UINTN                         HandleCount;
+  UINTN                         Index;
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;
+  VOID                          *Key;
+  EFI_FV_FILETYPE               FileType;
+  EFI_GUID                      NameGuid;
+  EFI_FV_FILE_ATTRIBUTES        FileAttributes;
+  UINTN                         Size;
+  UINTN                         FfsIndex;
+  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;
+  LIST_ENTRY                    *VfrDriverLink;
+
+  HandleBuffer = NULL;
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiFirmwareVolume2ProtocolGuid,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  //
+  // Search all FVs
+  //
+  for (Index = 0; Index < HandleCount; Index++) {
+    DEBUG ((EFI_D_INFO, "FvIndex - %x\n", Index));
+    Status = gBS->HandleProtocol (
+                    HandleBuffer[Index],
+                    &gEfiFirmwareVolume2ProtocolGuid,
+                    (VOID **) &Fv2
+                    );
+    ASSERT_EFI_ERROR (Status);
+
+    DEBUG_CODE (
+      EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL   *Fvb2;
+      EFI_PHYSICAL_ADDRESS                  FvAddress;
+      UINT64                                FvSize;
+
+      Status = gBS->HandleProtocol (
+                      HandleBuffer[Index],
+                      &gEfiFirmwareVolumeBlock2ProtocolGuid,
+                      (VOID **) &Fvb2
+                      );
+      ASSERT_EFI_ERROR (Status);
+      Status = Fvb2->GetPhysicalAddress (Fvb2, &FvAddress);
+      if (!EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_INFO, "FvAddress - 0x%08x\n", FvAddress));
+        FvSize = ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvAddress)->FvLength;
+        DEBUG ((EFI_D_INFO, "FvSize    - 0x%08x\n", FvSize));
+      }
+    );
+
+    if (ScanAll) {
+      //
+      // Need to parse all modules in all FVs.
+      //
+      Key = InternalVarCheckAllocateZeroPool (Fv2->KeySize);
+      ASSERT (Key != NULL);
+
+      for (FfsIndex = 0; ; FfsIndex++) {
+        FileType = EFI_FV_FILETYPE_ALL;
+        Status = Fv2->GetNextFile (
+                        Fv2,
+                        Key,
+                        &FileType,
+                        &NameGuid,
+                        &FileAttributes,
+                        &Size
+                      );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+
+        ParseFfs (Fv2, &NameGuid);
+      }
+
+      InternalVarCheckFreePool (Key);
+    } else {
+      //
+      // Only parse drivers in the VFR drivers list.
+      //
+      VfrDriverLink = mVfrDriverList.ForwardLink;
+      while (VfrDriverLink != &mVfrDriverList) {
+        VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
+        VfrDriverLink = VfrDriverLink->ForwardLink;
+        if (ParseFfs (Fv2, VfrDriverInfo->DriverGuid)) {
+          //
+          // Found the driver in the FV.
+          //
+          RemoveEntryList (&VfrDriverInfo->Link);
+          InternalVarCheckFreePool (VfrDriverInfo);
+        }
+      }
+    }
+  }
+
+  FreePool (HandleBuffer);
+}
+
+/**
+  Create Vfr Driver List.
+
+  @param[in] DriverGuidArray    Driver Guid Array
+
+**/
+VOID
+CreateVfrDriverList (
+  IN EFI_GUID   *DriverGuidArray
+  )
+{
+  UINTN                         Index;
+  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;
+
+  for (Index = 0; !CompareGuid (&DriverGuidArray[Index], &gZeroGuid); Index++) 
{
+     DEBUG ((EFI_D_INFO, "CreateVfrDriverList: %g\n", 
&DriverGuidArray[Index]));
+     VfrDriverInfo = InternalVarCheckAllocateZeroPool (sizeof 
(*VfrDriverInfo));
+     ASSERT (VfrDriverInfo != NULL);
+     VfrDriverInfo->Signature = VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE;
+     VfrDriverInfo->DriverGuid = &DriverGuidArray[Index];
+     InsertTailList (&mVfrDriverList, &VfrDriverInfo->Link);
+  }
+}
+
+/**
+  Destroy Vfr Driver List.
+
+**/
+VOID
+DestroyVfrDriverList (
+  VOID
+  )
+{
+  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;
+  LIST_ENTRY                    *VfrDriverLink;
+
+  while (mVfrDriverList.ForwardLink != &mVfrDriverList) {
+    VfrDriverLink = mVfrDriverList.ForwardLink;
+    VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
+    RemoveEntryList (&VfrDriverInfo->Link);
+    InternalVarCheckFreePool (VfrDriverInfo);
+  }
+}
+
+/**
+  Generate from FV.
+
+**/
+VOID
+VarCheckHiiGenFromFv (
+  VOID
+  )
+{
+  EFI_GUID      *DriverGuidArray;
+  BOOLEAN       ScanAll;
+
+  DEBUG ((EFI_D_INFO, "VarCheckHiiGenDxeFromFv\n"));
+
+  //
+  // Get vfr driver guid array from PCD.
+  //
+  DriverGuidArray = (EFI_GUID *) PcdGetPtr (PcdVarCheckVfrDriverGuidArray);
+
+  if (CompareGuid (&DriverGuidArray[0], &gZeroGuid)) {
+    //
+    // No VFR driver will be parsed from FVs.
+    //
+    return;
+  }
+
+  if (CompareGuid (&DriverGuidArray[0], &mAllFfGuid)) {
+    ScanAll = TRUE;
+  } else {
+    ScanAll = FALSE;
+    CreateVfrDriverList (DriverGuidArray);
+  }
+
+  ParseFv (ScanAll);
+
+  if (!ScanAll) {
+    DestroyVfrDriverList ();
+  }
+}
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
new file mode 100644
index 0000000..41cde34
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
@@ -0,0 +1,73 @@
+/** @file
+  Var Check Hii generation from Hii Database.
+
+Copyright (c) 2015, 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 "VarCheckHiiGen.h"
+
+/**
+  Generate from Hii Database.
+
+**/
+VOID
+VarCheckHiiGenFromHiiDatabase (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         BufferSize;
+  VOID                          *Buffer;
+  EFI_PHYSICAL_ADDRESS          BufferAddress;
+  EFI_HII_DATABASE_PROTOCOL     *HiiDatabase;
+
+  //
+  // Locate HII Database protocol
+  //
+  Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) 
&HiiDatabase);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  //
+  // Call first time with zero buffer length.
+  // Should fail with EFI_BUFFER_TOO_SMALL.
+  //
+  BufferSize = 0;
+  Buffer = NULL;
+  Status = HiiDatabase->ExportPackageLists (HiiDatabase, 0, &BufferSize, 
Buffer);
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    //
+    // Allocate buffer to hold the HII Database.
+    //
+    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 
EFI_SIZE_TO_PAGES (BufferSize), &BufferAddress);
+    ASSERT_EFI_ERROR (Status);
+    Buffer = (VOID *) (UINTN) BufferAddress;
+
+    //
+    // Export HII Database into the buffer.
+    //
+    Status = HiiDatabase->ExportPackageLists (HiiDatabase, 0, &BufferSize, 
Buffer);
+    ASSERT_EFI_ERROR (Status);
+
+    DEBUG ((EFI_D_INFO, "VarCheckHiiGenDxeFromHii - HII Database exported at 
0x%x, size = 0x%x\n", Buffer, BufferSize));
+
+#ifdef DUMP_HII_DATA
+    DEBUG_CODE (
+      DumpHiiDatabase (Buffer, BufferSize);
+      );
+#endif
+
+    VarCheckParseHiiDatabase (Buffer, BufferSize);
+
+    gBS->FreePages (BufferAddress, EFI_SIZE_TO_PAGES (BufferSize));
+  }
+}
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
new file mode 100644
index 0000000..24d24c5
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
@@ -0,0 +1,58 @@
+## @file
+#  NULL class library to register var check HII handler.
+#
+#  Copyright (c) 2015, 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.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VarCheckHiiLib
+  MODULE_UNI_FILE                = VarCheckHiiLib.uni
+  FILE_GUID                      = A34FBDD0-05D3-4AF7-A720-560E91AC8CDF
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+  CONSTRUCTOR                    = VarCheckHiiLibNullClassConstructor
+
+[Sources]
+  VarCheckHiiLibNullClass.c
+  VarCheckHii.h
+  VarCheckHiiGenFromFv.c
+  VarCheckHiiGenFromHii.c
+  VarCheckHiiGen.c
+  VarCheckHiiGen.h
+  InternalVarCheckStructure.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  UefiBootServicesTableLib
+  MemoryAllocationLib
+  PcdLib
+  VarCheckLib
+
+[Guids]
+  gZeroGuid                                 ## SOMETIMES_CONSUMES   ## GUID
+
+[Protocols]
+  gEfiFirmwareVolume2ProtocolGuid           ## SOMETIMES_CONSUMES
+  gEfiFirmwareVolumeBlock2ProtocolGuid      ## SOMETIMES_CONSUMES
+  gEfiHiiDatabaseProtocolGuid               ## SOMETIMES_CONSUMES
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVarCheckVfrDriverGuidArray   ## 
SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni
new file mode 100644
index 
0000000000000000000000000000000000000000..e4a0debafa7e603b2d2a64f9a92d070114027deb
GIT binary patch
literal 1766
zcmd6nPjAye5XI+=#CKSw7eH+SNL&y?B*cJ4siVYE;Z!+sn_A=#azabLJnir8CUzQv
z#0ga^@9xab&b)au>)YQgYnkJF#&Gt|F08Pro!eu3gjQ!KHnd}gvoR-`Eg6noVIwP%
zOS?f{*@C&`=7f_a@;Q>TD{rB@muSZJ9o;9384gWmbIX0a(wbGwhY|Zd8T}x)l6)p$
zU4i%s89ZfuY0vG2y|P30F*zvPDSO>1xurQnTd<pxnX@+MvZ%d@Me()tOkFYOSiZ52
z_3iB*E>bXvS%?1;zY`y0h8$Q_4aBkJF=JsfEOmCny*c&{jZmpF1-mKUYOYmD-BxAC
z?B*U>zU5!H^K}H(Rh^R21?m@PKe?e(Reggb#F}~38<avO%c9~(IW6eC`d-Hd)<r(P
zho#1P?YU4-{h4h626+^Qz?WjFBbD_CoZEE~t3rQ)K2%7Ue_^wW={_%kOLhKeeSfiL
zK!{dbysC3nRN}RNPwJ__t?WzBbd&5$>eJfceu-uT^4yMgPMUbR<f|D;c~uc;dUQ`>
zADP?s1v!RE2bWq?v@!iPWEXjUhrI4C`#v@s4>k8O{TyL2@SYQP>SN6fR{53J25ZO5
zk`A{popLU(iI3>)6sx{Rc7i^}t9&FrdLK#HrBlolTiGaTu=;?lqJLxk%!!ce{YC32
zA&bbqR(@*lF<kWMCdKUT{nP0G*YeoKslJ1%XTsYF{GH(`!H52dk)44^e2LjMY^C7&
z+c=<xdIJ;co-wQI)CouU64C}4{hvQ=qssH&a#V*5$WGnUtE#du&xey^6FxVUyaTAv
B5&r-H

literal 0
HcmV?d00001

diff --git a/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c 
b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
new file mode 100644
index 0000000..3afa796
--- /dev/null
+++ b/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
@@ -0,0 +1,539 @@
+/** @file
+  Var Check Hii handler.
+
+Copyright (c) 2015, 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 "VarCheckHii.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckHiiHex[] = {'0', '1', '2', 
'3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+/**
+  Dump some hexadecimal data.
+
+  @param[in] Indent     How many spaces to indent the output.
+  @param[in] Offset     The offset of the dump.
+  @param[in] DataSize   The size in bytes of UserData.
+  @param[in] UserData   The data to dump.
+
+**/
+VOID
+VarCheckHiiInternalDumpHex (
+  IN UINTN        Indent,
+  IN UINTN        Offset,
+  IN UINTN        DataSize,
+  IN VOID         *UserData
+  )
+{
+  UINT8 *Data;
+
+  CHAR8 Val[50];
+
+  CHAR8 Str[20];
+
+  UINT8 TempByte;
+  UINTN Size;
+  UINTN Index;
+
+  Data = UserData;
+  while (DataSize != 0) {
+    Size = 16;
+    if (Size > DataSize) {
+      Size = DataSize;
+    }
+
+    for (Index = 0; Index < Size; Index += 1) {
+      TempByte            = Data[Index];
+      Val[Index * 3 + 0]  = mVarCheckHiiHex[TempByte >> 4];
+      Val[Index * 3 + 1]  = mVarCheckHiiHex[TempByte & 0xF];
+      Val[Index * 3 + 2]  = (CHAR8) ((Index == 7) ? '-' : ' ');
+      Str[Index]          = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' 
: TempByte);
+    }
+
+    Val[Index * 3]  = 0;
+    Str[Index]      = 0;
+    DEBUG ((EFI_D_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, 
Str));
+
+    Data += Size;
+    Offset += Size;
+    DataSize -= Size;
+  }
+}
+
+/**
+  Var Check Hii Question.
+
+  @param[in] HiiQuestion    Pointer to Hii Question
+  @param[in] Data           Data pointer.
+  @param[in] DataSize       Size of Data to set.
+
+  @retval TRUE  Check pass
+  @retval FALSE Check fail.
+
+**/
+BOOLEAN
+VarCheckHiiQuestion (
+  IN VAR_CHECK_HII_QUESTION_HEADER  *HiiQuestion,
+  IN VOID                           *Data,
+  IN UINTN                          DataSize
+  )
+{
+  UINT64   OneData;
+  UINT64   Minimum;
+  UINT64   Maximum;
+  UINT64   OneValue;
+  UINT8    *Ptr;
+  UINT8    Index;
+  UINT8    MaxContainers;
+
+  if ((UINTN) (HiiQuestion->VarOffset + HiiQuestion->StorageWidth) > DataSize) 
{
+    DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + 
StorageWidth(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, 
HiiQuestion->StorageWidth, DataSize));
+    return FALSE;
+  }
+
+  OneData = 0;
+  CopyMem (&OneData, (UINT8 *) Data + HiiQuestion->VarOffset, 
HiiQuestion->StorageWidth);
+
+  switch (HiiQuestion->OpCode) {
+    case EFI_IFR_ONE_OF_OP:
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1);
+      while ((UINTN) Ptr < (UINTN) HiiQuestion + HiiQuestion->Length) {
+        OneValue = 0;
+        CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+        if (OneData == OneValue) {
+          //
+          // Match
+          //
+          break;
+        }
+        Ptr += HiiQuestion->StorageWidth;
+      }
+      if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+        //
+        // No match
+        //
+        DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: OneOf mismatch 
(0x%lx)\n", OneData));
+        DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, 
(UINT8 *) HiiQuestion););
+        return FALSE;
+      }
+      break;
+
+    case EFI_IFR_CHECKBOX_OP:
+      if ((OneData != 0) && (OneData != 1)) {
+        DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: CheckBox mismatch 
(0x%lx)\n", OneData));
+        DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, 
(UINT8 *) HiiQuestion););
+        return FALSE;
+      }
+      break;
+
+    case EFI_IFR_NUMERIC_OP:
+      Minimum = 0;
+      Maximum = 0;
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1);
+      CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+      Ptr += HiiQuestion->StorageWidth;
+      CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+      Ptr += HiiQuestion->StorageWidth;
+
+      //
+      // No need to check Step, because it is ONLY for UI.
+      //
+      if ((OneData < Minimum) || (OneData > Maximum)) {
+        DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: Numeric mismatch 
(0x%lx)\n", OneData));
+        DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, 
(UINT8 *) HiiQuestion););
+        return FALSE;
+      }
+      break;
+
+    case EFI_IFR_ORDERED_LIST_OP:
+      MaxContainers = ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) 
HiiQuestion)->MaxContainers;
+      if ((UINTN) (HiiQuestion->VarOffset + HiiQuestion->StorageWidth * 
MaxContainers) > DataSize) {
+        DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + 
StorageWidth(0x%02x) * MaxContainers(0x%02x)) > Size(0x%x)\n", 
HiiQuestion->VarOffset, HiiQuestion->StorageWidth, MaxContainers, DataSize));
+        return FALSE;
+      }
+      for (Index = 0; Index < MaxContainers; Index++) {
+        OneData = 0;
+        CopyMem (&OneData, (UINT8 *) Data + HiiQuestion->VarOffset + 
HiiQuestion->StorageWidth * Index, HiiQuestion->StorageWidth);
+        if (OneData == 0) {
+          //
+          // The value of 0 is used to determine if a particular "slot" in the 
array is empty.
+          //
+          continue;
+        }
+
+        Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 
1);
+        while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+          OneValue = 0;
+          CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+          if (OneData == OneValue) {
+            //
+            // Match
+            //
+            break;
+          }
+          Ptr += HiiQuestion->StorageWidth;
+        }
+        if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+          //
+          // No match
+          //
+          DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: OrderedList 
mismatch\n"));
+          DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, 
HiiQuestion->StorageWidth * MaxContainers, (UINT8 *) Data + 
HiiQuestion->VarOffset););
+          DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, 
(UINT8 *) HiiQuestion););
+          return FALSE;
+        }
+      }
+      break;
+
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+
+  return TRUE;
+}
+
+VAR_CHECK_HII_VARIABLE_HEADER   *mVarCheckHiiBin = NULL;
+UINTN                           mVarCheckHiiBinSize = 0;
+
+/**
+  SetVariable check handler HII.
+
+  @param[in] VariableName       Name of Variable to set.
+  @param[in] VendorGuid         Variable vendor GUID.
+  @param[in] Attributes         Attribute value of the variable.
+  @param[in] DataSize           Size of Data to set.
+  @param[in] Data               Data pointer.
+
+  @retval EFI_SUCCESS               The SetVariable check result was success.
+  @retval EFI_SECURITY_VIOLATION    Check fail.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerHii (
+  IN CHAR16     *VariableName,
+  IN EFI_GUID   *VendorGuid,
+  IN UINT32     Attributes,
+  IN UINTN      DataSize,
+  IN VOID       *Data
+  )
+{
+  VAR_CHECK_HII_VARIABLE_HEADER     *HiiVariable;
+  VAR_CHECK_HII_QUESTION_HEADER     *HiiQuestion;
+
+  if (mVarCheckHiiBin == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || 
(Attributes == 0)) {
+    //
+    // Do not check delete variable.
+    //
+    return EFI_SUCCESS;
+  }
+
+  //
+  // For Hii Variable header align.
+  //
+  HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN 
(mVarCheckHiiBin);
+  while ((UINTN) HiiVariable < ((UINTN) mVarCheckHiiBin + 
mVarCheckHiiBinSize)) {
+    if ((StrCmp ((CHAR16 *) (HiiVariable + 1), VariableName) == 0) &&
+        (CompareGuid (&HiiVariable->Guid, VendorGuid))) {
+      //
+      // Found the Hii Variable that could be used to do check.
+      //
+      DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - %s:%g with Attributes = 
0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
+      if (HiiVariable->Attributes != Attributes) {
+        DEBUG ((EFI_D_INFO, "VarCheckHiiVariable fail for Attributes - 
0x%08x\n", HiiVariable->Attributes));
+        return EFI_SECURITY_VIOLATION;
+      }
+
+      if (DataSize == 0) {
+        DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - CHECK PASS with DataSize == 
0 !\n"));
+        return EFI_SUCCESS;
+      }
+
+      if (HiiVariable->Size != DataSize) {
+        DEBUG ((EFI_D_INFO, "VarCheckHiiVariable fail for Size - 0x%x\n", 
HiiVariable->Size));
+        return EFI_SECURITY_VIOLATION;
+      }
+
+      //
+      // Do the check.
+      // For Hii Question header align.
+      //
+      HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) 
HiiVariable + HiiVariable->HeaderLength));
+      while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + 
HiiVariable->Length)) {
+        if (!VarCheckHiiQuestion (HiiQuestion, Data, DataSize)) {
+          return EFI_SECURITY_VIOLATION;
+        }
+        //
+        // For Hii Question header align.
+        //
+        HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) 
HiiQuestion + HiiQuestion->Length));
+      }
+
+      DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - ALL CHECK PASS!\n"));
+      return EFI_SUCCESS;
+    }
+    //
+    // For Hii Variable header align.
+    //
+    HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) 
HiiVariable + HiiVariable->Length));
+  }
+
+  // Not found, so pass.
+  return EFI_SUCCESS;
+}
+
+#ifdef DUMP_VAR_CHECK_HII
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING   
mHiiOpCodeStringTable[] = {
+  {EFI_IFR_VARSTORE_EFI_OP,     "EfiVarStore"},
+  {EFI_IFR_ONE_OF_OP,           "OneOf"},
+  {EFI_IFR_CHECKBOX_OP,         "CheckBox"},
+  {EFI_IFR_NUMERIC_OP,          "Numeric"},
+  {EFI_IFR_ORDERED_LIST_OP,     "OrderedList"},
+};
+
+/**
+  HII opcode to string.
+
+  @param[in] HiiOpCode  Hii OpCode.
+
+  @return Pointer to string.
+
+**/
+CHAR8 *
+HiiOpCodeToStr (
+  IN UINT8  HiiOpCode
+  )
+{
+  UINTN     Index;
+  for (Index = 0; Index < sizeof (mHiiOpCodeStringTable) / sizeof 
(mHiiOpCodeStringTable[0]); Index++) {
+    if (mHiiOpCodeStringTable[Index].HiiOpCode == HiiOpCode) {
+      return mHiiOpCodeStringTable[Index].HiiOpCodeStr;
+    }
+  }
+
+  return "<UnknownHiiOpCode>";
+}
+
+/**
+  Dump Hii Question.
+
+  @param[in] HiiQuestion    Pointer to Hii Question.
+
+**/
+VOID
+DumpHiiQuestion (
+  IN VAR_CHECK_HII_QUESTION_HEADER  *HiiQuestion
+  )
+{
+  UINT64    Minimum;
+  UINT64    Maximum;
+  UINT64    OneValue;
+  UINT8     *Ptr;
+
+  DEBUG ((EFI_D_INFO, "  VAR_CHECK_HII_QUESTION_HEADER\n"));
+  DEBUG ((EFI_D_INFO, "    OpCode        - 0x%02x (%a)\n", 
HiiQuestion->OpCode, HiiOpCodeToStr (HiiQuestion->OpCode)));
+  DEBUG ((EFI_D_INFO, "    Length        - 0x%02x\n", HiiQuestion->Length));
+  DEBUG ((EFI_D_INFO, "    VarOffset     - 0x%04x\n", HiiQuestion->VarOffset));
+  DEBUG ((EFI_D_INFO, "    StorageWidth  - 0x%02x\n", 
HiiQuestion->StorageWidth));
+
+  switch (HiiQuestion->OpCode) {
+    case EFI_IFR_ONE_OF_OP:
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1);
+      while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+        OneValue = 0;
+        CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+        switch (HiiQuestion->StorageWidth) {
+          case sizeof (UINT8):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%02x\n", OneValue));
+            break;
+          case sizeof (UINT16):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%04x\n", OneValue));
+            break;
+          case sizeof (UINT32):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%08x\n", OneValue));
+            break;
+          case sizeof (UINT64):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%016lx\n", OneValue));
+            break;
+          default:
+            ASSERT (FALSE);
+            break;
+        }
+        Ptr += HiiQuestion->StorageWidth;
+      }
+      break;
+
+    case EFI_IFR_CHECKBOX_OP:
+      break;
+
+    case EFI_IFR_NUMERIC_OP:
+      Minimum = 0;
+      Maximum = 0;
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1);
+      CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+      Ptr += HiiQuestion->StorageWidth;
+      CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+      Ptr += HiiQuestion->StorageWidth;
+
+      switch (HiiQuestion->StorageWidth) {
+        case sizeof (UINT8):
+          DEBUG ((EFI_D_INFO, "    Minimum       - 0x%02x\n", Minimum));
+          DEBUG ((EFI_D_INFO, "    Maximum       - 0x%02x\n", Maximum));
+          break;
+        case sizeof (UINT16):
+          DEBUG ((EFI_D_INFO, "    Minimum       - 0x%04x\n", Minimum));
+          DEBUG ((EFI_D_INFO, "    Maximum       - 0x%04x\n", Maximum));
+          break;
+        case sizeof (UINT32):
+          DEBUG ((EFI_D_INFO, "    Minimum       - 0x%08x\n", Minimum));
+          DEBUG ((EFI_D_INFO, "    Maximum       - 0x%08x\n", Maximum));
+          break;
+        case sizeof (UINT64):
+          DEBUG ((EFI_D_INFO, "    Minimum       - 0x%016lx\n", Minimum));
+          DEBUG ((EFI_D_INFO, "    Maximum       - 0x%016lx\n", Maximum));
+          break;
+        default:
+          ASSERT (FALSE);
+          break;
+      }
+      break;
+
+    case EFI_IFR_ORDERED_LIST_OP:
+      DEBUG ((EFI_D_INFO, "    MaxContainers - 0x%02x\n", 
((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion)->MaxContainers));
+      Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 1);
+      while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+        OneValue = 0;
+        CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+        switch (HiiQuestion->StorageWidth) {
+          case sizeof (UINT8):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%02x\n", OneValue));
+            break;
+          case sizeof (UINT16):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%04x\n", OneValue));
+            break;
+          case sizeof (UINT32):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%08x\n", OneValue));
+            break;
+          case sizeof (UINT64):
+            DEBUG ((EFI_D_INFO, "    OneOfOption   - 0x%016lx\n", OneValue));
+            break;
+          default:
+            ASSERT (FALSE);
+            break;
+        }
+        Ptr += HiiQuestion->StorageWidth;
+      }
+      break;
+
+    default:
+      ASSERT (FALSE);
+      break;
+  }
+}
+
+/**
+  Dump Hii Variable.
+
+  @param[in] HiiVariable    Pointer to Hii Variable.
+
+**/
+VOID
+DumpHiiVariable (
+  IN VAR_CHECK_HII_VARIABLE_HEADER  *HiiVariable
+  )
+{
+  VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+  DEBUG ((EFI_D_INFO, "VAR_CHECK_HII_VARIABLE_HEADER\n"));
+  DEBUG ((EFI_D_INFO, "  Revision        - 0x%04x\n", HiiVariable->Revision));
+  DEBUG ((EFI_D_INFO, "  HeaderLength    - 0x%04x\n", 
HiiVariable->HeaderLength));
+  DEBUG ((EFI_D_INFO, "  Length          - 0x%08x\n", HiiVariable->Length));
+  DEBUG ((EFI_D_INFO, "  OpCode          - 0x%02x (%a)\n", 
HiiVariable->OpCode, HiiOpCodeToStr (HiiVariable->OpCode)));
+  DEBUG ((EFI_D_INFO, "  Size            - 0x%04x\n", HiiVariable->Size));
+  DEBUG ((EFI_D_INFO, "  Attributes      - 0x%08x\n", 
HiiVariable->Attributes));
+  DEBUG ((EFI_D_INFO, "  Guid            - %g\n", &HiiVariable->Guid));
+  DEBUG ((EFI_D_INFO, "  Name            - %s\n", HiiVariable + 1));
+
+  //
+  // For Hii Question header align.
+  //
+  HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) 
HiiVariable + HiiVariable->HeaderLength));
+  while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + HiiVariable->Length)) {
+    //
+    // Dump Hii Question related to the Hii Variable.
+    //
+    DumpHiiQuestion (HiiQuestion);
+    //
+    // For Hii Question header align.
+    //
+    HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) 
HiiQuestion + HiiQuestion->Length));
+  }
+}
+
+/**
+  Dump Var Check HII.
+
+  @param[in] VarCheckHiiBin     Pointer to VarCheckHiiBin.
+  @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
+
+**/
+VOID
+DumpVarCheckHii (
+  IN VOID   *VarCheckHiiBin,
+  IN UINTN  VarCheckHiiBinSize
+  )
+{
+  VAR_CHECK_HII_VARIABLE_HEADER     *HiiVariable;
+
+  DEBUG ((EFI_D_INFO, "DumpVarCheckHii\n"));
+
+  //
+  // For Hii Variable header align.
+  //
+  HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN 
(VarCheckHiiBin);
+  while ((UINTN) HiiVariable < ((UINTN) VarCheckHiiBin + VarCheckHiiBinSize)) {
+    DumpHiiVariable (HiiVariable);
+    //
+    // For Hii Variable header align.
+    //
+    HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) 
HiiVariable + HiiVariable->Length));
+  }
+}
+#endif
+
+/**
+  Constructor function of VarCheckHiiLib to register var check HII handler.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The constructor executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckHiiLibNullClassConstructor (
+  IN EFI_HANDLE             ImageHandle,
+  IN EFI_SYSTEM_TABLE       *SystemTable
+  )
+{
+  VarCheckLibRegisterEndOfDxeCallback (VarCheckHiiGen);
+  VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckHiiBin);
+  VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerHii);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 4cd9c4d..c0e9d32 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -974,6 +974,12 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
   # @Prompt Set NX for stack.
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f
 
+  ## This PCD to include the driver guid of VFR drivers for VarCheckHiiBin 
generation.<BR><BR>
+  # Default is gZeroGuid that means no VFR driver will be parsed for 
VarCheckHiiBin generation.<BR>
+  # If it is set to an all FFs GUID, it means all modules in all FVs will be 
parsed for VarCheckHiiBin generation.<BR>
+  # @Prompt Driver guid array of VFR drivers for VarCheckHiiBin generation.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVarCheckVfrDriverGuidArray|{ 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00 }|VOID*|0x3000103A
+
 [PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   ## This PCD defines the Console output row. The default value is 25 
according to UEFI spec.
   #  This PCD could be set to 0 then console output would be at max column and 
max row.
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 7b14e61..4416c07 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -280,6 +280,7 @@ [Components]
   MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
   MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
   MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+  MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
 
   MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
   MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf
@@ -375,6 +376,7 @@ [Components.IA32, Components.X64, Components.Ebc]
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+      NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
   }
   MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf
   
@@ -384,6 +386,7 @@ [Components.IA32, Components.X64]
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+      NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
   }
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
   MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
diff --git a/MdeModulePkg/MdeModulePkg.uni b/MdeModulePkg/MdeModulePkg.uni
index 
27c0db73afe95aca106ace7a24d843a4d805e7b7..9db6e58e165898f02e3dbad097d0fd84f3f8ea03
 100644
GIT binary patch
delta 685
zcmew{f&0xI?hOT>jKdfb8HyO388R4B8Il>Y8NwLSfP5Dq&SWS9iWM=qGn4|^DGZK4
zb`el@<>bcA=Gh2&1%`B}3I(uPU^NU14EaEl6oBTrF$4kW6eJUif&4U}d=Xe4)qW44
zU6~9{K%57ZO$WLlZ~DcJjHP5b^rNETbORwqq3Iv?FtPE1j7(<80XjB?A$7X_OeV>2
zgv+VsT2PoxH&ka5o!sNbF<I-ws>u%AQj=@uNtmWHM1cb|A0DI%3?;yTPXv+*47otL
zM4$^nfs+Re9B9x@_Wv$DJ#RfDn{5F&bc=z?Qh<^qgdfaB(vuB7ECIWw&Xa>Vlc8jK
zycVOlEXYz&%;f-~0x-7Rz)o;y2xahOaGAW&Q(O}!mkV@O3NZL`fF^>R35g?^tQ$kv
c^!W9RqLe$dcKQW&Mx*8>pSCag#CYW@09=un&;S4c

delta 22
gcmV+x0O|kioD2An3$SqVlYsd)gPQoan)m_I)s{95fdBvi

-- 
1.9.5.msysgit.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to