From 1241af9510c6f7c0ff83cc3c418e9e1e24bf1ab1 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Tue, 25 Aug 2015 03:10:04 +0000 Subject: [PATCH] MdeModulePkg: Add VarCheckHiiLib NULL class library The check will be based on VarCheckHiiBin that generated from FV and Hii Database. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18293 6f19259b-4bc3-4df7-8a09-765794883524 --- .../InternalVarCheckStructure.h | 82 + .../Library/VarCheckHiiLib/VarCheckHii.h | 63 + .../Library/VarCheckHiiLib/VarCheckHiiGen.c | 1483 +++++++++++++++++ .../Library/VarCheckHiiLib/VarCheckHiiGen.h | 136 ++ .../VarCheckHiiLib/VarCheckHiiGenFromFv.c | 443 +++++ .../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 0000000000..a9faed48d9 --- /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.
+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 0000000000..d770785490 --- /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.
+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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#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 0000000000..725ccc7d78 --- /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.
+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 ""; +} + +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 ""; +} + +/** + 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 0000000000..f81be2ea88 --- /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.
+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 0000000000..21fc80e89c --- /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.
+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 0000000000..41cde34af7 --- /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.
+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 0000000000..24d24c5dd5 --- /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.
+# +# 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>1xurQnTdbXvS%?1;zY`y0h8$Q_4aBkJF=JsfEOmCny*c&{jZmpF1-mKUYOYmD-BxAC z?B*U>zU5!H^K}H(Rh^R21?m@PKe?e(Reggb#F}~38eJfceu-uT^4yMgPMUbR 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 +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 ""; +} + +/** + 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 4cd9c4dd89..c0e9d32e04 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -974,6 +974,12 @@ # @Prompt Set NX for stack. gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f + ## This PCD to include the driver guid of VFR drivers for VarCheckHiiBin generation.

+ # Default is gZeroGuid that means no VFR driver will be parsed for VarCheckHiiBin generation.
+ # If it is set to an all FFs GUID, it means all modules in all FVs will be parsed for VarCheckHiiBin generation.
+ # @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 ee928989ca..c211d7f0ed 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -280,6 +280,7 @@ 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 @@ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf { NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf + NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf } MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf @@ -384,6 +386,7 @@ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf { 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!sNbFu%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 -- 2.39.2