* [Patch v3 0/3] BaseTools: Move FCE & FMMT tools to edk2 repo
@ 2019-07-01 11:27 Liming Gao
2019-07-01 11:27 ` [Patch v3 1/3] BaseTools: Add a tool BfmLib Liming Gao
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Liming Gao @ 2019-07-01 11:27 UTC (permalink / raw)
To: devel
Cc: Bob Feng, Ard Biesheuvel, Leif Lindholm, Michael D Kinney,
Cetola Stephano
REF:FMMT(https://bugzilla.tianocore.org/show_bug.cgi?id=1847)
FCE(https://bugzilla.tianocore.org/show_bug.cgi?id=1848)
Changes are committed in forked repository:
https://github.com/shenglei10/edk2/commits/movetool
FCE & FMMT tools are in https://firmware.intel.com/develop
Intel UEFI tools and utilities. Now, this patch moves them
to edk2 repo BaseTools directory. Besides, this patch updates
their license header to BSD-2-Clause-Patent, and does some
bug fixes.
In V2:
Without ARM/AARCH64 Linux build verification, and give the
proposal to move it to edk2-platform Platform\Intel\Tools
https://edk2.groups.io/g/devel/message/42545
In V3:
Collect more feedback in edk2 community and Design Meeting.
https://edk2.groups.io/g/announce/message/49
One option is to ask help for the people who work on ARM/AARCH64 Linux
to compile these patch set before those patches are pushed.
Now, these patches have been reviewed and tested on IA32/X64.
I plan to push them on July 3rd (UTC+8 10AM). If you find any issue,
please let me know. After push, if you find any break, please
let me know.
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Cetola Stephano <stephano.cetola@intel.com>
Shenglei Zhang (3):
BaseTools/BfmLib: Add BfmLib to edk2/master
BaseTools/FCE: Add FCE tool to edk2/master
BaseTools/FMMT: Add a new tool FMMT
BaseTools/Source/C/BfmLib/BfmLib.c | 4355 +++++++++++++
BaseTools/Source/C/BfmLib/BinFileManager.c | 1024 ++++
BaseTools/Source/C/FCE/BinaryCreate.c | 216 +
BaseTools/Source/C/FCE/BinaryParse.c | 1326 ++++
BaseTools/Source/C/FCE/Common.c | 2183 +++++++
BaseTools/Source/C/FCE/Expression.c | 2367 +++++++
BaseTools/Source/C/FCE/Fce.c | 6449 ++++++++++++++++++++
BaseTools/Source/C/FCE/IfrParse.c | 4836 +++++++++++++++
BaseTools/Source/C/FCE/MonotonicBasedVariable.c | 874 +++
BaseTools/Source/C/FCE/TimeBasedVariable.c | 878 +++
BaseTools/Source/C/FCE/Variable.c | 1091 ++++
BaseTools/Source/C/FMMT/FirmwareModuleManagement.c | 2559 ++++++++
BaseTools/Source/C/FMMT/FmmtLib.c | 5051 +++++++++++++++
BaseTools/Source/C/FMMT/Rebase.c | 846 +++
BaseTools/BinWrappers/PosixLike/BfmLib | 29 +
BaseTools/BinWrappers/PosixLike/FCE | 29 +
BaseTools/BinWrappers/PosixLike/FMMT | 29 +
BaseTools/Source/C/BfmLib/BinFileManager.h | 439 ++
BaseTools/Source/C/BfmLib/GNUmakefile | 15 +
BaseTools/Source/C/BfmLib/Makefile | 17 +
BaseTools/Source/C/FCE/BinaryCreate.h | 157 +
BaseTools/Source/C/FCE/BinaryParse.h | 187 +
BaseTools/Source/C/FCE/Common.h | 999 +++
BaseTools/Source/C/FCE/Fce.h | 447 ++
BaseTools/Source/C/FCE/GNUmakefile | 55 +
BaseTools/Source/C/FCE/IfrParse.h | 789 +++
BaseTools/Source/C/FCE/Makefile | 19 +
BaseTools/Source/C/FCE/MonotonicBasedVariable.h | 162 +
BaseTools/Source/C/FCE/TimeBasedVariable.h | 166 +
BaseTools/Source/C/FCE/Variable.h | 154 +
BaseTools/Source/C/FCE/VariableCommon.h | 55 +
BaseTools/Source/C/FMMT/FirmwareModuleManagement.h | 479 ++
BaseTools/Source/C/FMMT/FmmtConf.ini | 6 +
BaseTools/Source/C/FMMT/GNUmakefile | 16 +
BaseTools/Source/C/FMMT/Makefile | 17 +
BaseTools/Source/C/FMMT/Rebase.h | 31 +
BaseTools/Source/C/GNUmakefile | 5 +-
BaseTools/Source/C/Makefile | 5 +-
38 files changed, 38360 insertions(+), 2 deletions(-)
create mode 100644 BaseTools/Source/C/BfmLib/BfmLib.c
create mode 100644 BaseTools/Source/C/BfmLib/BinFileManager.c
create mode 100644 BaseTools/Source/C/FCE/BinaryCreate.c
create mode 100644 BaseTools/Source/C/FCE/BinaryParse.c
create mode 100644 BaseTools/Source/C/FCE/Common.c
create mode 100644 BaseTools/Source/C/FCE/Expression.c
create mode 100644 BaseTools/Source/C/FCE/Fce.c
create mode 100644 BaseTools/Source/C/FCE/IfrParse.c
create mode 100644 BaseTools/Source/C/FCE/MonotonicBasedVariable.c
create mode 100644 BaseTools/Source/C/FCE/TimeBasedVariable.c
create mode 100644 BaseTools/Source/C/FCE/Variable.c
create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.c
create mode 100644 BaseTools/Source/C/FMMT/FmmtLib.c
create mode 100644 BaseTools/Source/C/FMMT/Rebase.c
create mode 100755 BaseTools/BinWrappers/PosixLike/BfmLib
create mode 100755 BaseTools/BinWrappers/PosixLike/FCE
create mode 100755 BaseTools/BinWrappers/PosixLike/FMMT
create mode 100644 BaseTools/Source/C/BfmLib/BinFileManager.h
create mode 100644 BaseTools/Source/C/BfmLib/GNUmakefile
create mode 100644 BaseTools/Source/C/BfmLib/Makefile
create mode 100644 BaseTools/Source/C/FCE/BinaryCreate.h
create mode 100644 BaseTools/Source/C/FCE/BinaryParse.h
create mode 100644 BaseTools/Source/C/FCE/Common.h
create mode 100644 BaseTools/Source/C/FCE/Fce.h
create mode 100644 BaseTools/Source/C/FCE/GNUmakefile
create mode 100644 BaseTools/Source/C/FCE/IfrParse.h
create mode 100644 BaseTools/Source/C/FCE/Makefile
create mode 100644 BaseTools/Source/C/FCE/MonotonicBasedVariable.h
create mode 100644 BaseTools/Source/C/FCE/TimeBasedVariable.h
create mode 100644 BaseTools/Source/C/FCE/Variable.h
create mode 100644 BaseTools/Source/C/FCE/VariableCommon.h
create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.h
create mode 100644 BaseTools/Source/C/FMMT/FmmtConf.ini
create mode 100644 BaseTools/Source/C/FMMT/GNUmakefile
create mode 100644 BaseTools/Source/C/FMMT/Makefile
create mode 100644 BaseTools/Source/C/FMMT/Rebase.h
--
2.13.0.windows.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Patch v3 1/3] BaseTools: Add a tool BfmLib
2019-07-01 11:27 [Patch v3 0/3] BaseTools: Move FCE & FMMT tools to edk2 repo Liming Gao
@ 2019-07-01 11:27 ` Liming Gao
2019-07-01 11:27 ` [Patch v3 2/3] BaseTools: Add a tool FCE Liming Gao
2019-07-01 11:27 ` [Patch v3 3/3] BaseTools: Add a tool FMMT Liming Gao
2 siblings, 0 replies; 4+ messages in thread
From: Liming Gao @ 2019-07-01 11:27 UTC (permalink / raw)
To: devel; +Cc: Shenglei Zhang, Bob Feng
From: Shenglei Zhang <shenglei.zhang@intel.com>
BmfLib is added for FCE tool.
https://bugzilla.tianocore.org/show_bug.cgi?id=1848
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
Reviewed-by: Bob Feng <bob.c.feng@intel.com>
---
BaseTools/Source/C/BfmLib/BfmLib.c | 4355 ++++++++++++++++++++++++++++
BaseTools/Source/C/BfmLib/BinFileManager.c | 1024 +++++++
BaseTools/BinWrappers/PosixLike/BfmLib | 29 +
BaseTools/Source/C/BfmLib/BinFileManager.h | 439 +++
BaseTools/Source/C/BfmLib/GNUmakefile | 15 +
BaseTools/Source/C/BfmLib/Makefile | 17 +
BaseTools/Source/C/GNUmakefile | 1 +
BaseTools/Source/C/Makefile | 1 +
8 files changed, 5881 insertions(+)
create mode 100644 BaseTools/Source/C/BfmLib/BfmLib.c
create mode 100644 BaseTools/Source/C/BfmLib/BinFileManager.c
create mode 100755 BaseTools/BinWrappers/PosixLike/BfmLib
create mode 100644 BaseTools/Source/C/BfmLib/BinFileManager.h
create mode 100644 BaseTools/Source/C/BfmLib/GNUmakefile
create mode 100644 BaseTools/Source/C/BfmLib/Makefile
diff --git a/BaseTools/Source/C/BfmLib/BfmLib.c b/BaseTools/Source/C/BfmLib/BfmLib.c
new file mode 100644
index 0000000000..9dedda3da2
--- /dev/null
+++ b/BaseTools/Source/C/BfmLib/BfmLib.c
@@ -0,0 +1,4355 @@
+/** @file
+
+ Library to process EFI image.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinFileManager.h"
+
+#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
+ ( \
+ (BOOLEAN) ( \
+ (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
+ ) \
+ )
+
+#ifndef __GNUC__
+#define DECODE_STR "%s -d -o \"%s\" \"%s\" > NUL"
+#define ENCODE_STR "%s -e \"%s\" -o \"%s\" > NUL"
+#define GENSEC_COMPRESSION "GenSec -s %s -c %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_GUID "GenSec -s %s -r PROCESSING_REQUIRED -g %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_STR "GenSec -s %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_ALIGN "GenSec --sectionalign 16 \"%s\" -o \"%s\" > NUL"
+#define GENFV_STR "GenFv -i \"%s\" -o \"%s\" > NUL"
+#define GENFV_FVGUID "GenFv -i \"%s\" -o \"%s\" --FvNameGuid %s > NUL"
+#define GENFV_FFS "GenFv -f \"%s\" -g %s -o \"%s\" > NUL"
+#define GENFFS_STR "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" > NUL"
+#define GENFFS_FIX "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" > NUL"
+#else
+#define DECODE_STR "%s -d -o \"%s\" \"%s\" > /dev/null"
+#define ENCODE_STR "%s -e \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_COMPRESSION "GenSec -s %s -c %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_GUID "GenSec -s %s -r PROCESSING_REQUIRED -g %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_STR "GenSec -s %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_ALIGN "GenSec --sectionalign 16 \"%s\" -o \"%s\" > /dev/null"
+#define GENFV_STR "GenFv -i \"%s\" -o \"%s\" > /dev/null"
+#define GENFV_FVGUID "GenFv -i \"%s\" -o \"%s\" --FvNameGuid %s > /dev/null"
+#define GENFV_FFS "GenFv -f \"%s\" -g %s -o \"%s\" > /dev/null"
+#define GENFFS_STR "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" > /dev/null"
+#define GENFFS_FIX "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" > /dev/null"
+#endif
+
+#define DECODE_STR_ERR "%s -d -o \"%s\" \"%s\" "
+#define ENCODE_STR_ERR "%s -e \"%s\" -o \"%s\" "
+
+CHAR8 mFirmwareFileSystem2Guid[16] = {0x78, 0xE5, 0x8C, 0x8C, 0x3D, 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3};
+
+CHAR8 mFirmwareFileSystem3Guid[16] = {0x7A, 0xC0, 0x73, 0x54, 0xCB, 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A };
+extern CHAR8* mGuidToolDefinition;
+UINT32 PadSizeOfBfv;
+
+static CHAR8 *mSectionTypeName[] = {
+ NULL, // 0x00 - reserved
+ "EFI_SECTION_COMPRESSION", // 0x01
+ "EFI_SECTION_GUID_DEFINED", // 0x02
+ NULL, // 0x03 - reserved
+ NULL, // 0x04 - reserved
+ NULL, // 0x05 - reserved
+ NULL, // 0x06 - reserved
+ NULL, // 0x07 - reserved
+ NULL, // 0x08 - reserved
+ NULL, // 0x09 - reserved
+ NULL, // 0x0A - reserved
+ NULL, // 0x0B - reserved
+ NULL, // 0x0C - reserved
+ NULL, // 0x0D - reserved
+ NULL, // 0x0E - reserved
+ NULL, // 0x0F - reserved
+ "EFI_SECTION_PE32", // 0x10
+ "EFI_SECTION_PIC", // 0x11
+ "EFI_SECTION_TE", // 0x12
+ "EFI_SECTION_DXE_DEPEX", // 0x13
+ "EFI_SECTION_VERSION", // 0x14
+ "EFI_SECTION_USER_INTERFACE", // 0x15
+ "EFI_SECTION_COMPATIBILITY16", // 0x16
+ "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17
+ "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18
+ "EFI_SECTION_RAW", // 0x19
+ NULL, // 0x1A
+ "EFI_SECTION_PEI_DEPEX", // 0x1B
+ "EFI_SECTION_SMM_DEPEX" // 0x1C
+};
+
+
+static CHAR8 *mFfsFileType[] = {
+ NULL, // 0x00
+ "EFI_FV_FILETYPE_RAW", // 0x01
+ "EFI_FV_FILETYPE_FREEFORM", // 0x02
+ "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03
+ "EFI_FV_FILETYPE_PEI_CORE", // 0x04
+ "EFI_FV_FILETYPE_DXE_CORE", // 0x05
+ "EFI_FV_FILETYPE_PEIM", // 0x06
+ "EFI_FV_FILETYPE_DRIVER", // 0x07
+ "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
+ "EFI_FV_FILETYPE_APPLICATION", // 0x09
+ "EFI_FV_FILETYPE_SMM", // 0x0A
+ "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
+ "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C
+ "EFI_FV_FILETYPE_SMM_CORE" // 0x0D
+ };
+
+FV_INFORMATION *
+LibInitializeFvStruct (
+ FV_INFORMATION *Fv
+)
+{
+ UINT32 Index;
+
+ if (Fv == NULL) {
+ return NULL;
+ }
+
+ memset (Fv, '\0', sizeof (FV_INFORMATION));
+
+ for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index ++) {
+ memset (Fv->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+ memset (Fv->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+
+ Fv->FfsAttuibutes[Index].IsLeaf = TRUE;
+ Fv->FfsAttuibutes[Index].TotalSectionNum = 0;
+ }
+
+ Fv->PatchData = NULL;
+ Fv->EncapData = NULL;
+ Fv->FvNext = NULL;
+ Fv->FvLevel = 0;
+ Fv->IsBfvFlag = FALSE;
+ Fv->IsInputFvFlag = FALSE;
+
+ return Fv;
+}
+
+/**
+ Generate the unique template filename.
+**/
+CHAR8 *
+GenTempFile (
+ VOID
+ )
+{
+ CHAR8 *TemString;
+ TemString = NULL;
+#ifndef __GNUC__
+ TemString = CloneString (tmpnam (NULL));
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ TemString = CloneString(tmp);
+ close(Fdtmp);
+#endif
+ return TemString;
+}
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+)
+{
+ FIRMWARE_DEVICE *LocalFdData;
+ UINT16 Index;
+ CHAR8 Ffs2Guid[16];
+ CHAR8 SignatureCheck[4];
+ CHAR8 Signature[5] = "_FVH";
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *NewFoundFv;
+ BOOLEAN FirstMatch;
+ UINT32 FdSize;
+ UINT16 FvCount;
+ VOID *FdBuffer;
+ VOID *FdBufferOri;
+ UINT32 Count;
+
+
+ CurrentFv = NULL;
+ NewFoundFv = NULL;
+ FdBuffer = NULL;
+ FdBufferOri = NULL;
+ FirstMatch = TRUE;
+ Index = 0;
+ FdSize = 0;
+ FvCount = 0;
+ Count = 0;
+ LocalFdData = NULL;
+
+ if (InputFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Find each FVs in the FD
+ //
+
+ fseek(InputFile,0,SEEK_SET);
+ fseek(InputFile,0,SEEK_END);
+
+ FdSize = ftell(InputFile);
+
+ fseek(InputFile,0,SEEK_SET);
+ //
+ // Create an FD structure to store useful information.
+ //
+ LocalFdData = (FIRMWARE_DEVICE *) calloc (sizeof (FIRMWARE_DEVICE), sizeof(UINT8));
+ if (LocalFdData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ LocalFdData->Fv = (FV_INFORMATION *) calloc (sizeof (FV_INFORMATION), sizeof(UINT8));
+ if (LocalFdData->Fv == NULL) {
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ LibInitializeFvStruct (LocalFdData->Fv);
+
+ //
+ // Readout the FD file data to buffer.
+ //
+ FdBuffer = malloc (FdSize);
+
+ if (FdBuffer == NULL) {
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (FdBuffer, 1, FdSize, InputFile) != FdSize) {
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ FdBufferOri = FdBuffer;
+
+ for (Count=0; Count < FdSize - 4; Count++) {
+ //
+ // Copy 4 bytes of fd data to check the _FVH signature
+ //
+ memcpy (SignatureCheck, FdBuffer, 4);
+ FdBuffer =(UINT8 *)FdBuffer + 4;
+
+ if (strncmp(SignatureCheck, Signature, 4) == 0){
+ //
+ // Still need to determine the FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER equal to
+ // EFI_FIRMWARE_FILE_SYSTEM2_GUID.
+ // Turn back 28 bytes to find the GUID.
+ //
+ FdBuffer = (UINT8 *)FdBuffer - 28;
+ memcpy (Ffs2Guid, FdBuffer, 16);
+
+ //
+ // Compare GUID.
+ //
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem2Guid[Index]) {
+ break;
+ }
+ }
+ if (Index != 16) {
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem3Guid[Index]) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Point to the original address
+ //
+ FdBuffer = (UINT8 *)FdBuffer + 28;
+
+ //
+ // Here we found an FV.
+ //
+ if (Index == 16) {
+ if (FirstMatch) {
+ LocalFdData->Fv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri) - 0x2c;
+ CurrentFv = LocalFdData->Fv;
+ CurrentFv->FvNext = NULL;
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(CurrentFv->FvName, "FV%d", FvCount);
+
+ FirstMatch = FALSE;
+ } else {
+ NewFoundFv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION));
+ if (NULL == NewFoundFv) {
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LibInitializeFvStruct (NewFoundFv);
+
+ //
+ // Need to turn back 0x2c bytes
+ //
+ NewFoundFv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri) - 0x2c;
+
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(NewFoundFv->FvName, "FV%d", FvCount);
+
+ //
+ // Value it to NULL for found FV usage.
+ //
+ NewFoundFv->FvNext = NULL;
+ CurrentFv->FvNext = NewFoundFv;
+
+ //
+ // Make the CurrentFv point to next FV.
+ //
+ CurrentFv = CurrentFv->FvNext;
+ }
+
+ FvCount ++;
+ Index = 0;
+ }
+
+ }
+
+ //
+ // We need to turn back 3 bytes.
+ //
+ FdBuffer = (UINT8 *)FdBuffer - 3;
+ }
+
+ LocalFdData->Size = FdSize;
+
+ *FdData = LocalFdData;
+
+ free (FdBufferOri);
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+
+ UINTN BytesRead;
+ UINT32 Size;
+ EFI_FV_BLOCK_MAP_ENTRY BlockMap;
+
+ BytesRead = 0;
+ Size = 0;
+
+ if (InputFile == NULL || FvSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), SEEK_CUR);
+ do {
+ fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+
+ if (BlockMap.NumBlocks != 0) {
+ Size += BlockMap.NumBlocks * BlockMap.Length;
+ }
+ } while (!(BlockMap.NumBlocks == 0 && BlockMap.Length == 0));
+
+
+ *FvSize = Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Expands the 3 byte size commonly used in Firmware Volume data structures
+
+ @param[in] Size - Address of the 3 byte array representing the size
+
+ @return UINT32
+
+**/
+UINT32
+FvBufExpand3ByteSize (
+ IN VOID* Size
+ )
+{
+ return (((UINT8*)Size)[2] << 16) +
+ (((UINT8*)Size)[1] << 8) +
+ ((UINT8*)Size)[0];
+}
+
+/**
+
+ Clears out all files from the Fv buffer in memory
+
+ @param[in] Fv - Address of the Fv in memory
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+FvBufGetSize (
+ IN VOID *Fv,
+ OUT UINTN *Size
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FV_BLOCK_MAP_ENTRY *blk;
+
+ *Size = 0;
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ blk = hdr->BlockMap;
+
+ while (blk->Length != 0 || blk->NumBlocks != 0) {
+ *Size = *Size + (blk->Length * blk->NumBlocks);
+ if (*Size >= 0x40000000) {
+ //
+ // If size is greater than 1GB, then assume it is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+ blk++;
+ }
+
+ if (*Size == 0) {
+ //
+ // If size is 0, then assume the volume is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+
+ Iterates through the files contained within the firmware volume
+
+ @param[in] Fv - Address of the Fv in memory
+ @param[in] Key - Should be 0 to get the first file. After that, it should be
+ passed back in without modifying it's contents to retrieve
+ subsequent files.
+ @param[in] File- Output file pointer
+ File == NULL - invalid parameter
+ otherwise - *File will be update to the location of the file
+
+ @return EFI_STATUS
+ EFI_NOT_FOUND
+ EFI_VOLUME_CORRUPTED
+
+**/
+EFI_STATUS
+FvBufFindNextFile (
+ IN VOID *Fv,
+ IN OUT UINTN *Key,
+ OUT VOID **File
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FFS_FILE_HEADER *fhdr;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN fsize;
+ EFI_STATUS Status;
+ UINTN fvSize;
+
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ fhdr = NULL;
+
+ if (Fv == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FvBufGetSize (Fv, &fvSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (*Key == 0) {
+ if (hdr->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) hdr + hdr->ExtHeaderOffset);
+ *Key = (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSize;
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8);
+ } else {
+ *Key = hdr->HeaderLength;
+ }
+ }
+
+ FvbAttributes = hdr->Attributes;
+
+ for(
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8);
+ (*Key + sizeof (*fhdr)) < fvSize;
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8)
+ ) {
+ fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
+ fsize = GetFfsFileLength (fhdr);
+ if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_VALID
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_INVALID
+ )
+ ) {
+ *Key = *Key + 1;
+ continue;
+ } else if(
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_MARKED_FOR_UPDATE
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DELETED
+ )
+ ) {
+ *Key = *Key + fsize;
+ continue;
+ } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DATA_VALID
+ )
+ ) {
+ *File = (UINT8*)hdr + *Key;
+ *Key = *Key + fsize;
+ return EFI_SUCCESS;
+ }
+
+ *Key = *Key + 1;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/*
+ Generate the leaf FFS files.
+
+*/
+EFI_STATUS
+LibGenFfsFile (
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ErasePolarity
+)
+{
+ UINT32 FfsFileSize;
+ CHAR8 *FfsFileName;
+ FILE *FfsFile;
+ CHAR8 *TempDir;
+ CHAR8 TempBuf[_MAX_PATH];
+
+ FfsFileSize = 0;
+ FfsFileName = NULL;
+ FfsFile = NULL;
+ TempDir = NULL;
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ FfsFileName = (CHAR8 *) malloc (_MAX_PATH);
+ if (NULL == FfsFileName) {
+ return EFI_ABORTED;
+ }
+ memset (FfsFileName, '\0', _MAX_PATH);
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ sprintf (
+ TempBuf,
+ "-Num%d-%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X-Level%d",
+ *FfsCount,
+ (unsigned) CurrentFile->Name.Data1,
+ CurrentFile->Name.Data2,
+ CurrentFile->Name.Data3,
+ CurrentFile->Name.Data4[0],
+ CurrentFile->Name.Data4[1],
+ CurrentFile->Name.Data4[2],
+ CurrentFile->Name.Data4[3],
+ CurrentFile->Name.Data4[4],
+ CurrentFile->Name.Data4[5],
+ CurrentFile->Name.Data4[6],
+ CurrentFile->Name.Data4[7],
+ Level
+ );
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) + strlen(TempBuf) > _MAX_PATH - 1) {
+ free(FfsFileName);
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strcpy (FfsFileName, TempDir);
+ strncat (FfsFileName, OS_SEP_STR, _MAX_PATH - strlen (FfsFileName) - 1);
+ strncat (FfsFileName, CurrentFv->FvName, _MAX_PATH - strlen (FfsFileName) - 1);
+ strncat (FfsFileName, TempBuf, _MAX_PATH - strlen (FfsFileName) - 1);
+
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].FfsName, FfsFileName, strlen(FfsFileName));
+
+ //
+ // Update current FFS files file state.
+ //
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ FfsFile = fopen (FfsFileName, "wb+");
+ if (FfsFile == NULL) {
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) != FfsFileSize) {
+ fclose(FfsFile);
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ fclose(FfsFile);
+ free(FfsFileName);
+ FfsFileName = NULL;
+
+ CurrentFv->FfsNumbers = *FfsCount;
+
+ *FfsCount += 1;
+
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+BOOLEAN
+LibCheckPadFfsContainFvNameGuid (
+ IN FV_INFORMATION *CurrentFv,
+ IN EFI_FFS_FILE_HEADER2 *CurrentFile
+)
+{
+ UINT32 FfsFileSize;
+ UINT32 FfsDataSize;
+ EFI_GUID *FfsData;
+ ENCAP_INFO_DATA *LocalEncapData;
+
+ LocalEncapData = NULL;
+
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsDataSize = FfsFileSize - GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsData = (EFI_GUID *) ((INT8 *)CurrentFile + GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile));
+
+ if (FfsDataSize == 0) {
+ return TRUE;
+ }
+
+ LocalEncapData = CurrentFv->EncapData;
+
+ do {
+ if (LocalEncapData->FvExtHeader != NULL) {
+ if (CompareGuid(FfsData, &LocalEncapData->FvExtHeader->FvName) == 0) {
+ return TRUE;
+ }
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ } while (LocalEncapData->NextNode != NULL);
+
+ return FALSE;
+}
+
+BOOLEAN
+LibCheckPadFfsNotNull (
+ IN EFI_FFS_FILE_HEADER2 *CurrentFile
+)
+{
+ UINT32 FfsFileSize;
+ UINT32 FfsDataSize;
+ INT8 *FfsData;
+
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsDataSize = FfsFileSize - GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsData = (INT8 *)CurrentFile + GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ if (FfsDataSize == 0) {
+ return FALSE;
+ }
+
+ while (FfsDataSize > 0) {
+ if (((FfsData[FfsDataSize-1]) & 0xFF) != 0xFF) {
+ return TRUE;
+ }
+ FfsDataSize--;
+ }
+
+ return FALSE;
+}
+
+/**
+ Find a maximum length of free space in PAD FFS of Bfv.
+
+ @PadFfsHeader - The header of PAD FFS file
+
+ @return The length of free space
+
+**/
+UINT32
+GetBfvMaxFreeSpace (
+ IN EFI_FFS_FILE_HEADER2 *PadFfsHeader
+ )
+{
+ UINT32 FfsSize;
+ UINT32 Count;
+ UINT32 Index;
+ UINT32 MaxSize;
+ UINT32 HeaderSize;
+
+ Index = 0;
+ MaxSize = 0;
+
+ if (PadFfsHeader == NULL) {
+ return MaxSize;
+ }
+
+ FfsSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) PadFfsHeader);
+ HeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) PadFfsHeader);
+
+ for (Count = HeaderSize; Count < FfsSize; Count++) {
+ if (((((INT8 *)PadFfsHeader)[Count]) & 0xFF) == 0xFF) {
+ Index++;
+ } else {
+ if (Index > MaxSize) {
+ MaxSize = Index;
+ }
+ Index = 0;
+ }
+ }
+ return MaxSize;
+}
+
+
+/**
+
+ Get the Offset and data of PAD FFS file in FV file.
+ This function should be only called for find an PAD FFS contain additional data
+ (usually will contain FIT table data or reset vector.)
+
+ BFV:
+ ---------------------- <- Low
+ | |
+ | |
+ -----------------------
+ | FFSs ... |
+ -----------------------
+ | |
+ | |
+ -----------------------
+ | PAD FFS file |
+ | |
+ | reset vector |
+ | |
+ | FIT table |
+ -----------------------
+ | SEC CORE | <- High
+ -----------------------
+
+**/
+
+EFI_STATUS
+LibFindResetVectorAndFitTableData(
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvImage,
+ IN EFI_FFS_FILE_HEADER2 *CurrentFile,
+ IN OUT FV_INFORMATION *CurrentFv
+)
+{
+ UINT32 Count1;
+ UINT32 Count2;
+ UINT32 FfsFileSize;
+ BOOLEAN FfsFoundFlag;
+ UINT32 FfsOffset;
+ UINT32 DataOffset;
+ UINT32 HeaderSize;
+ PATCH_DATA_PAD_FFS *LocalPatchData;
+
+ FfsFileSize = 0;
+ Count1 = 0;
+ Count2 = 0;
+ FfsOffset = 0;
+ DataOffset = 0;
+ FfsFoundFlag = FALSE;
+ LocalPatchData = NULL;
+
+ if (CurrentFv == NULL || CurrentFile == NULL || FvImage == NULL) {
+ return EFI_ABORTED;
+ }
+
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ HeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ for (Count1=0; Count1 < (FvImage->FvLength - FfsFileSize); Count1 ++) {
+ for (Count2=0; Count2 < FfsFileSize; Count2 ++) {
+ if (((INT8*)FvImage)[Count1 + Count2] != ((INT8 *) CurrentFile)[Count2]){
+ break;
+ }
+ }
+ if (Count2 == FfsFileSize) {
+ FfsFoundFlag = TRUE;
+ FfsOffset = Count1;
+ break;
+ }
+ }
+
+ if (FfsFoundFlag) {
+ //
+ // Find data in FFS file;
+ // Will skip FFS header;
+ //
+ for (Count1 = HeaderSize; Count1 < FfsFileSize; Count1++) {
+ if (((((INT8 *)CurrentFile)[Count1]) & 0xFF) != 0xFF) {
+ DataOffset = FfsOffset + Count1;
+ break;
+ }
+ }
+
+ if (CurrentFv->PatchData == NULL) {
+ //
+ // First time found data.
+ //
+ CurrentFv->PatchData = (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATCH_DATA_PAD_FFS));
+ if (CurrentFv->PatchData == NULL) {
+ return EFI_ABORTED;
+ }
+
+ CurrentFv->PatchData->Offset = DataOffset;
+ CurrentFv->PatchData->Data = malloc(FfsFileSize - Count1);
+ CurrentFv->PatchData->Length = FfsFileSize - Count1;
+ CurrentFv->PatchData->NextNode = NULL;
+
+ if (CurrentFv->PatchData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (CurrentFv->PatchData->Data, (INT8 *)CurrentFile + Count1, FfsFileSize - Count1);
+ } else {
+ LocalPatchData = CurrentFv->PatchData;
+
+ while (LocalPatchData->NextNode != NULL) {
+ LocalPatchData = LocalPatchData->NextNode;
+ }
+
+ LocalPatchData = (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATCH_DATA_PAD_FFS));
+
+ if (LocalPatchData == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalPatchData->Offset = DataOffset;
+ LocalPatchData->Data = malloc(FfsFileSize - Count1);
+ LocalPatchData->Length = FfsFileSize - Count1;
+ LocalPatchData->NextNode = NULL;
+
+ if (LocalPatchData->Data == NULL) {
+ free (LocalPatchData);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalPatchData->Data, (INT8 *)CurrentFile + Count1, FfsFileSize - Count1);
+ while (CurrentFv->PatchData->NextNode != NULL) {
+ CurrentFv->PatchData = CurrentFv->PatchData->NextNode;
+ }
+ CurrentFv->PatchData->NextNode = LocalPatchData;
+ }
+
+ } else {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Construct a set of blank chars based on the number.
+
+ @param[in] Count The number of blank chars.
+
+ @return A string contained the blank chars.
+
+*/
+CHAR8 *
+LibConstructBlankChar (
+ IN UINT8 Count
+)
+{
+ CHAR8 *RetStr;
+ UINT8 Index;
+
+ Index = 0;
+ RetStr = NULL;
+
+ RetStr = (CHAR8 *) malloc (Count +1);
+
+ if (NULL == RetStr) {
+ return NULL;
+ }
+
+ memset (RetStr , '\0', Count + 1);
+
+ for (Index=0; Index <= Count -1; Index ++) {
+ RetStr[Index] = ' ';
+ }
+
+ return RetStr;
+
+}
+
+VOID
+Unicode2AsciiString (
+ IN CHAR16 *Source,
+ OUT CHAR8 *Destination
+ )
+ /*++
+
+ Routine Description:
+
+ Convert a null-terminated unicode string to a null-terminated ascii string.
+
+ Arguments:
+
+ Source - The pointer to the null-terminated input unicode string.
+ Destination - The pointer to the null-terminated output ascii string.
+
+ Returns:
+
+ N/A
+
+ --*/
+{
+ while (*Source != '\0') {
+ *(Destination++) = (CHAR8) *(Source++);
+ }
+ //
+ // End the ascii with a NULL.
+ //
+ *Destination = '\0';
+}
+
+
+/**
+
+ Parses EFI Sections, if the view flag turn on, then will collect FFS section information
+ and extract FFS files.
+
+ @param[in] SectionBuffer - Buffer containing the section to parse.
+ @param[in] BufferLength - Length of SectionBuffer
+ @param[in, out] CurrentFv
+ @param[in] FvName
+ @param[in] CurrentFile
+ @param[in] Level
+ @param[in, out] FfsCount
+ @param[in] ViewFlag
+ @param[in] ErasePolarity
+
+ @retval EFI_SECTION_ERROR - Problem with section parsing.
+ (a) compression errors
+ (b) unrecognized section
+ @retval EFI_UNSUPPORTED - Do not know how to parse the section.
+ @retval EFI_SUCCESS - Section successfully parsed.
+ @retval EFI_OUT_OF_RESOURCES - Memory allocation failed.
+
+--*/
+EFI_STATUS
+LibParseSection (
+ UINT8 *SectionBuffer,
+ UINT32 BufferLength,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ViewFlag,
+ BOOLEAN ErasePolarity,
+ BOOLEAN FfsGeneratedFlag
+ )
+{
+ UINT32 ParsedLength;
+ UINT8 *Ptr;
+ UINT32 SectionLength;
+ UINT32 UiSectionLength;
+ EFI_SECTION_TYPE Type;
+ EFI_STATUS Status;
+ CHAR8 *ExtractionTool;
+ CHAR8 *ToolInputFile;
+ CHAR8 *ToolOutputFile;
+ CHAR8 *SystemCommand;
+ UINT8 *ToolOutputBuffer;
+ UINT32 ToolOutputLength;
+ CHAR16 *UIName;
+ UINT32 UINameSize;
+ BOOLEAN HasDepexSection;
+ UINT32 NumberOfSections;
+ BOOLEAN IsFfsGenerated;
+ ENCAP_INFO_DATA *LocalEncapData;
+ CHAR8 *BlankChar;
+ UINT8 *UncompressedBuffer;
+ UINT32 UncompressedLength;
+ UINT8 *CompressedBuffer;
+ UINT32 CompressedLength;
+ UINT8 CompressionType;
+ DECOMPRESS_FUNCTION DecompressFunction;
+ GETINFO_FUNCTION GetInfoFunction;
+ UINT32 DstSize;
+ UINT32 ScratchSize;
+ UINT8 *ScratchBuffer;
+ BOOLEAN EncapDataNeedUpdata;
+ CHAR8 *TempDir;
+ CHAR8 *ToolInputFileFullName;
+ CHAR8 *ToolOutputFileFullName;
+ UINT8 LargeHeaderOffset;
+ CHAR8 *UIFileName;
+ CHAR8 *ToolInputFileName;
+ CHAR8 *ToolOutputFileName;
+
+ ParsedLength = 0;
+ ToolOutputLength = 0;
+ UINameSize = 0;
+ NumberOfSections = 0;
+ UncompressedLength = 0;
+ CompressedLength = 0;
+ CompressionType = 0;
+ DstSize = 0;
+ ScratchSize = 0;
+ Ptr = NULL;
+ ExtractionTool = NULL;
+ ToolInputFile = NULL;
+ ToolOutputFile = NULL;
+ SystemCommand = NULL;
+ ToolOutputBuffer = NULL;
+ UIName = NULL;
+ LocalEncapData = NULL;
+ BlankChar = NULL;
+ UncompressedBuffer = NULL;
+ CompressedBuffer = NULL;
+ ScratchBuffer = NULL;
+ TempDir = NULL;
+ ToolInputFileFullName = NULL;
+ ToolOutputFileFullName = NULL;
+ ToolInputFileName = NULL;
+ ToolOutputFileName = NULL;
+ HasDepexSection = FALSE;
+ IsFfsGenerated = FfsGeneratedFlag;
+ EncapDataNeedUpdata = TRUE;
+ LargeHeaderOffset = 0;
+
+
+ while (ParsedLength < BufferLength) {
+ Ptr = SectionBuffer + ParsedLength;
+
+ SectionLength = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if (SectionLength == 0xffffff && Type == 0xff) {
+ ParsedLength += 4;
+ continue;
+ }
+ //
+ //If Size is 0xFFFFFF then ExtendedSize contains the size of the section.
+ //
+ if (SectionLength == 0xffffff) {
+ SectionLength = ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSize;
+ LargeHeaderOffset = sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+
+ switch (Type) {
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+ EncapDataNeedUpdata = TRUE;
+
+ Level ++;
+ NumberOfSections ++;
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdata = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_FV_SECTION;
+
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ //
+ LocalEncapData->Data = NULL;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ Status = LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, FfsCount, ViewFlag, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+ break;
+
+ case EFI_SECTION_COMPRESSION:
+ Level ++;
+ NumberOfSections ++;
+
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdata = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_COMPRESS_SECTION;
+
+ //
+ // Store the compress type
+ //
+ LocalEncapData->Data = malloc (sizeof (UINT8));
+
+ if (LocalEncapData->Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ //
+ // Process compressed section
+ //
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ UncompressedBuffer = NULL;
+ CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION) - LargeHeaderOffset;
+ UncompressedLength = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+
+ if (CompressedLength != UncompressedLength) {
+ printf ("Error. File is not compressed, but the compressed length does not match the uncompressed length.\n");
+ return EFI_SECTION_ERROR;
+ }
+
+ UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ GetInfoFunction = EfiGetInfo;
+ DecompressFunction = EfiDecompress;
+
+ CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+
+ Status = GetInfoFunction (CompressedBuffer, CompressedLength, &DstSize, &ScratchSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+
+ if (DstSize != UncompressedLength) {
+ return EFI_SECTION_ERROR;
+ }
+
+ ScratchBuffer = malloc (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UncompressedBuffer = malloc (UncompressedLength);
+
+ if (UncompressedBuffer == NULL) {
+ free (ScratchBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Decompress the section.
+ //
+ Status = DecompressFunction (
+ CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ ScratchBuffer,
+ ScratchSize
+ );
+ free (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ free (UncompressedBuffer);
+ return EFI_SECTION_ERROR;
+ }
+ } else {
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection ( UncompressedBuffer,
+ UncompressedLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated);
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ //
+ // We need to deallocate Buffer
+ //
+ free (UncompressedBuffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ //
+ // Process GUID defined
+ // looks up the appropriate tool to use for extracting
+ // a GUID defined FV section.
+ //
+ Level ++;
+ NumberOfSections++;
+
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdata = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ if (EncapDataNeedUpdata) {
+
+ //
+ // Put in this is an FFS with FV section
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_GUIDED_SECTION;
+
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ //
+
+ LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID));
+
+ if (LocalEncapData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid, sizeof (EFI_GUID));
+
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid
+ );
+
+ if ((((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
+ //
+ // Not require process, directly gets data.
+ //
+ Status = LibParseSection (
+ Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+ } else if (ExtractionTool != NULL) {
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ ToolInputFile = GenTempFile ();
+ ToolOutputFile = GenTempFile ();
+ ToolInputFileName = strrchr(ToolInputFile, OS_SEP);
+ ToolOutputFileName = strrchr(ToolOutputFile, OS_SEP);
+
+ ToolInputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolInputFileName) + 1);
+ if (ToolInputFileFullName == NULL) {
+ free (ExtractionTool);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolOutputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolOutputFileName) + 1);
+ if (ToolOutputFileFullName == NULL) {
+ free (ToolInputFileFullName);
+ free (ExtractionTool);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName);
+ sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileName);
+
+ //
+ // Construction 'system' command string
+ //
+ SystemCommand = malloc (
+ strlen (DECODE_STR) +
+ strlen (ExtractionTool) +
+ strlen (ToolInputFileFullName) +
+ strlen (ToolOutputFileFullName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ExtractionTool);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ DECODE_STR,
+ ExtractionTool,
+ ToolOutputFileFullName,
+ ToolInputFileFullName
+ );
+
+ Status = PutFileImage (
+ ToolInputFileFullName,
+ (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset
+ );
+
+ if (HasDepexSection) {
+ HasDepexSection = FALSE;
+ }
+
+ if (EFI_ERROR (Status)) {
+ free(SystemCommand);
+ free (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ return EFI_SECTION_ERROR;
+ }
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ SystemCommand = malloc (
+ strlen (DECODE_STR_ERR) +
+ strlen (ExtractionTool) +
+ strlen (ToolInputFileFullName) +
+ strlen (ToolOutputFileFullName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (ExtractionTool);
+ LibRmDir (TempDir);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ DECODE_STR_ERR,
+ ExtractionTool,
+ ToolOutputFileFullName,
+ ToolInputFileFullName
+ );
+ system (SystemCommand);
+ printf("Command failed: %s\n", SystemCommand);
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ LibRmDir (TempDir);
+ free(SystemCommand);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ return EFI_ABORTED;
+ }
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ free (SystemCommand);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ ToolInputFile = NULL;
+ ToolInputFileFullName = NULL;
+
+
+ Status = GetFileImage (
+ ToolOutputFileFullName,
+ (CHAR8 **)&ToolOutputBuffer,
+ &ToolOutputLength
+ );
+ remove (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ ToolOutputFile = NULL;
+ ToolOutputFileFullName = NULL;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection (
+ ToolOutputBuffer,
+ ToolOutputLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+ } else {
+ //
+ // We don't know how to parse it now.
+ //
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ printf(" EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in %s file.\n", mGuidToolDefinition);
+ printf(" Its GUID is: ");
+ PrintGuid(&(((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->SectionDefinitionGuid));
+ return EFI_UNSUPPORTED;
+ }
+
+ break;
+
+ //
+ //Leaf sections
+ //
+ case EFI_SECTION_RAW:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PE32:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PIC:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_TE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_COMPATIBILITY16:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_VERSION:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ break;
+ case EFI_SECTION_PEI_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ break;
+ case EFI_SECTION_DXE_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ break;
+ case EFI_SECTION_SMM_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ break;
+
+ case EFI_SECTION_USER_INTERFACE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+ UiSectionLength = FvBufExpand3ByteSize (((EFI_USER_INTERFACE_SECTION *) Ptr)->CommonHeader.Size);
+ if (UiSectionLength == 0xffffff) {
+ UiSectionLength = ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonHeader.ExtendedSize;
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER2);
+ } else {
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER);
+ }
+
+ UIName = (CHAR16 *) malloc (UINameSize + 2);
+ if (UIName != NULL) {
+ memset (UIName, '\0', UINameSize + 2);
+ if (UiSectionLength >= 0xffffff) {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameString, UINameSize);
+ } else {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UINameSize);
+ }
+ } else {
+ return EFI_ABORTED;
+ }
+
+ BlankChar = LibConstructBlankChar( CurrentFv->FvLevel * 2);
+ if (BlankChar == NULL) {
+ free (UIName);
+ return EFI_ABORTED;
+ }
+
+ if (ViewFlag) {
+ UIFileName = malloc (UINameSize + 2);
+ if (UIFileName == NULL) {
+ free(BlankChar);
+ free(UIName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Unicode2AsciiString (UIName, UIFileName);
+ fprintf(stdout, "%sFile \"%s\"\n", BlankChar, UIFileName);
+ free(UIFileName);
+ }
+
+ free (BlankChar);
+ BlankChar = NULL;
+
+ //
+ // If Ffs file has been generated, then the FfsCount should decrease 1.
+ //
+ if (IsFfsGenerated) {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UINameSize);
+ } else {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UINameSize);
+ }
+ HasDepexSection = FALSE;
+ free(UIName);
+ UINameSize = 0;
+
+ break;
+ default:
+ break;
+ }
+
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+
+ if (ParsedLength < BufferLength) {
+ return EFI_SECTION_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Add function description
+
+ FvImage - add argument description
+ FileHeader - add argument description
+ ErasePolarity - add argument description
+
+ EFI_SUCCESS - Add description for return value
+ EFI_ABORTED - Add description for return value
+
+**/
+EFI_STATUS
+LibGetFileInfo (
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ BOOLEAN ErasePolarity,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ViewFlag
+ )
+{
+ UINT32 FileLength;
+ UINT8 FileState;
+ UINT8 Checksum;
+ EFI_FFS_FILE_HEADER2 BlankHeader;
+ EFI_STATUS Status;
+ ENCAP_INFO_DATA *LocalEncapData;
+ BOOLEAN EncapDataNeedUpdateFlag;
+ UINT32 FfsFileHeaderSize;
+
+ Status = EFI_SUCCESS;
+
+ LocalEncapData = NULL;
+ EncapDataNeedUpdateFlag = TRUE;
+
+ FfsFileHeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FileLength = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ //
+ // Check if we have free space
+ //
+ if (ErasePolarity) {
+ memset (&BlankHeader, -1, FfsFileHeaderSize);
+ } else {
+ memset (&BlankHeader, 0, FfsFileHeaderSize);
+ }
+
+ //
+ // Is this FV blank?
+ //
+ if (memcmp (&BlankHeader, CurrentFile, FfsFileHeaderSize) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Print file information.
+ //
+ FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)CurrentFile);
+
+ if (FileState == EFI_FILE_DATA_VALID) {
+ //
+ // Calculate header checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize);
+ Checksum = (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum.File);
+ Checksum = (UINT8) (Checksum - CurrentFile->State);
+ if (Checksum != 0) {
+ return EFI_ABORTED;
+ }
+
+ if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ //
+ // Calculate file checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFileHeaderSize), FileLength - FfsFileHeaderSize);
+ Checksum = Checksum + CurrentFile->IntegrityCheck.Checksum.File;
+ if (Checksum != 0) {
+ return EFI_ABORTED;
+ }
+ } else {
+ if (CurrentFile->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+ return EFI_ABORTED;
+ }
+ }
+ } else {
+ return EFI_ABORTED;
+ }
+
+ Level += 1;
+
+ if (CurrentFile->Type != EFI_FV_FILETYPE_ALL) {
+
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdateFlag = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (EncapDataNeedUpdateFlag) {
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_FFS;
+ LocalEncapData->FvExtHeader = NULL;
+
+ //
+ // Store the header of FFS file.
+ //
+ LocalEncapData->Data = malloc (FfsFileHeaderSize);
+ if (LocalEncapData->Data == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+
+ LocalEncapData->NextNode = NULL;
+ }
+
+ if ( CurrentFile->Type == EFI_FV_FILETYPE_FREEFORM ){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ }else if ( CurrentFile->Type == EFI_FV_FILETYPE_RAW){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag){
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ } else if ( CurrentFile->Type == EFI_FV_FILETYPE_SECURITY_CORE){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ //
+ // If an FV contain SECCORE, this FV will be considered as BFV.
+ //
+ CurrentFv->IsBfvFlag = TRUE;
+ if (!ViewFlag){
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ } else if( CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD){
+ //
+ // First check whether the FFS file contain FvExtended FvNameGuid information.
+ //
+ if (!LibCheckPadFfsContainFvNameGuid (CurrentFv, CurrentFile)) {
+ //
+ // Then check whether the PAD file have no additional data or not.
+ //
+ if (LibCheckPadFfsNotNull (CurrentFile)) {
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ //
+ // Get the size of PAD in BFV
+ //
+ PadSizeOfBfv = GetBfvMaxFreeSpace (CurrentFile);
+ if (!ViewFlag){
+ //
+ //LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ //
+ Status = LibFindResetVectorAndFitTableData (FvImage, CurrentFile, CurrentFv);
+ if (EFI_ERROR (Status)) {
+ printf ("Find reset vector and FIT table data failed. \n");
+ return EFI_ABORTED;
+ }
+ }
+ }
+ }
+ } else {
+ //
+ // All other files have sections
+ //
+ Status = LibParseSection (
+ (UINT8 *) ((UINTN) CurrentFile + FfsFileHeaderSize),
+ FileLength - FfsFileHeaderSize,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ FALSE
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ printf ("Error while parse the FFS file.\n");
+ return EFI_ABORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get firmware information. Including the FV headers,
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN UINT32 *FfsCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfFiles;
+ BOOLEAN ErasePolarity;
+ UINTN FvSize;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ UINTN Key;
+ ENCAP_INFO_DATA *LocalEncapData;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHdrPtr;
+
+ NumberOfFiles = 0;
+ Key = 0;
+ LocalEncapData = NULL;
+ CurrentFile = NULL;
+
+ Level += 1;
+ CurrentFv->FvLevel += 1;
+
+ Status = FvBufGetSize (Fv, &FvSize);
+
+ ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE;
+
+ if (!IsChildFv) {
+ //
+ // Write FV header information into CurrentFv struct.
+ //
+ CurrentFv->FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (CurrentFv->FvHeader == NULL) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV Header information
+ //
+ memcpy (CurrentFv->FvHeader, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ CurrentFv->FvExtHeader = NULL;
+
+ //
+ // Exist Extend FV header.
+ //
+ if (CurrentFv->FvHeader->ExtHeaderOffset != 0){
+ CurrentFv->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
+
+ if (CurrentFv->FvExtHeader == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy (CurrentFv->FvExtHeader, (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset), sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (mFvGuidIsSet) {
+ if (CompareGuid (&CurrentFv->FvExtHeader->FvName, &mFvNameGuid) == 0) {
+ CurrentFv->IsInputFvFlag = TRUE;
+ }
+ }
+
+ }
+
+ }
+
+ //
+ // Put encapsulate information into structure.
+ //
+ if (CurrentFv->EncapData == NULL && !IsChildFv) {
+ //
+ // First time in, the root FV
+ //
+ CurrentFv->EncapData = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (CurrentFv->EncapData == NULL) {
+ return EFI_ABORTED;
+ }
+ CurrentFv->EncapData->FvExtHeader = NULL;
+ CurrentFv->EncapData->Level = Level;
+ CurrentFv->EncapData->Type = BFM_ENCAP_TREE_FV;
+ CurrentFv->EncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (CurrentFv->EncapData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset);
+ CurrentFv->EncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+ if (CurrentFv->EncapData->FvExtHeader == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(CurrentFv->EncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ if (mFvGuidIsSet) {
+ if (CompareGuid (&CurrentFv->EncapData->FvExtHeader->FvName, &mFvNameGuid) == 0) {
+ CurrentFv->IsInputFvFlag = TRUE;
+ }
+ }
+
+ }
+
+ CurrentFv->EncapData->NextNode = NULL;
+
+ } else if (CurrentFv->EncapData == NULL) {
+ return EFI_ABORTED;
+ } else if (IsChildFv) {
+
+ LocalEncapData = CurrentFv->EncapData;
+
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_FV;
+ LocalEncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ LocalEncapData->FvExtHeader = NULL;
+
+ if (LocalEncapData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(ExtHdrPtr->ExtHeaderSize);
+
+ if (LocalEncapData->FvExtHeader == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(LocalEncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ }
+
+ LocalEncapData->NextNode = NULL;
+
+ }
+
+
+ //
+ // Get the first file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ printf ("Failed to find the first file from Fv. \n");
+ return Status;
+ }
+
+ while (CurrentFile != NULL) {
+
+ //
+ // Increment the number of files counter
+ //
+ NumberOfFiles++;
+
+ //
+ // Store FFS file Header information
+ //
+ CurrentFv->FfsHeader[*FfsCount].Attributes = CurrentFile->Attributes;
+ CurrentFv->FfsHeader[*FfsCount].IntegrityCheck = CurrentFile->IntegrityCheck;
+ CurrentFv->FfsHeader[*FfsCount].Name = CurrentFile->Name;
+ CurrentFv->FfsHeader[*FfsCount].Size[0] = CurrentFile->Size[0];
+ CurrentFv->FfsHeader[*FfsCount].Size[1] = CurrentFile->Size[1];
+ CurrentFv->FfsHeader[*FfsCount].Size[2] = CurrentFile->Size[2];
+ CurrentFv->FfsHeader[*FfsCount].State = CurrentFile->State;
+ CurrentFv->FfsHeader[*FfsCount].Type = CurrentFile->Type;
+ CurrentFv->FfsHeader[*FfsCount].ExtendedSize = CurrentFile->ExtendedSize;
+
+ //
+ // Display info about this file
+ //
+ Status = LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, FvName, Level, FfsCount, ViewFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the next file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+LibGenExtFile(
+ CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtPtr,
+ FILE *InfFile
+)
+{
+ CHAR8 *TempDir;
+ FILE *ExtFile;
+ CHAR8 OutputExtFile[_MAX_PATH];
+ CHAR8 Line[512];
+ size_t Len;
+
+ TempDir = NULL;
+
+ TempDir = getcwd(NULL, _MAX_PATH);
+
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ sprintf(
+ Line,
+ "%c%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X%d.ext",
+ OS_SEP,
+ (unsigned)ExtPtr->FvName.Data1,
+ ExtPtr->FvName.Data2,
+ ExtPtr->FvName.Data3,
+ ExtPtr->FvName.Data4[0],
+ ExtPtr->FvName.Data4[1],
+ ExtPtr->FvName.Data4[2],
+ ExtPtr->FvName.Data4[3],
+ ExtPtr->FvName.Data4[4],
+ ExtPtr->FvName.Data4[5],
+ ExtPtr->FvName.Data4[6],
+ ExtPtr->FvName.Data4[7],
+ ExtPtr->ExtHeaderSize
+ );
+ if (strlen (TempDir) + strlen (Line) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strncpy (OutputExtFile, TempDir, _MAX_PATH - 1);
+ OutputExtFile[_MAX_PATH - 1] = 0;
+ strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1);
+
+
+ ExtFile = fopen(OutputExtFile, "wb+");
+ if (ExtFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) != ExtPtr->ExtHeaderSize) {
+ fclose(ExtFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(ExtFile);
+
+ strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME = ");
+ if (strlen (Line) + strlen (OutputExtFile) + 1 > sizeof(Line) / sizeof (CHAR8) - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strncat (Line, OutputExtFile, sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ Len = strlen(Line);
+ if (fwrite(Line, 1, Len, InfFile) != Len) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ )
+{
+ UINT32 OccupiedSize;
+
+ OccupiedSize = ActualSize;
+ while ((OccupiedSize & (Alignment - 1)) != 0) {
+ OccupiedSize++;
+ }
+
+ return OccupiedSize;
+}
+
+/**
+ Converts ASCII characters to Unicode.
+ Assumes that the Unicode characters are only these defined in the ASCII set.
+
+ String - Pointer to string that is written to FILE.
+ UniString - Pointer to unicode string
+
+ The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+ IN CHAR8 *String,
+ OUT CHAR16 *UniString
+ )
+{
+ while (*String != '\0') {
+ *(UniString++) = (CHAR16) *(String++);
+ }
+ //
+ // End the UniString with a NULL.
+ //
+ *UniString = '\0';
+}
+
+
+EFI_STATUS
+LibCreateGuidedSectionOriginalData(
+ IN CHAR8* FileIn,
+ IN CHAR8* ToolName,
+ IN CHAR8* FileOut
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+ if (FileIn == NULL ||
+ ToolName == NULL ||
+ FileOut == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SystemCommand = malloc (
+ strlen (ENCODE_STR) +
+ strlen (FileIn) +
+ strlen (ToolName) +
+ strlen (FileOut) +
+ 1
+ );
+
+ if (NULL == SystemCommand) {
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ ENCODE_STR,
+ ToolName,
+ FileIn,
+ FileOut
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ SystemCommand = malloc (
+ strlen (ENCODE_STR_ERR) +
+ strlen (FileIn) +
+ strlen (ToolName) +
+ strlen (FileOut) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ ENCODE_STR_ERR,
+ ToolName,
+ FileIn,
+ FileOut
+ );
+ system (SystemCommand);
+ printf("Command failed: %s\n", SystemCommand);
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function convert the FV header's attribute to a string. The converted string
+ will be put into an INF file as the input of GenFV.
+
+ @param[in] Attr FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+ @retval EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+LibFvHeaderAttributeToStr (
+ IN EFI_FVB_ATTRIBUTES_2 Attr,
+ IN FILE* InfFile
+)
+{
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ LocalStr = (CHAR8 *) malloc (1024 * 4);
+
+ if (LocalStr == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', 1024 * 4);
+
+ if (Attr == 0 || InfFile == NULL) {
+ free (LocalStr);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ strncat (LocalStr, "[attributes] \n", sizeof("[attributes] \n"));
+
+ if (Attr & EFI_FVB2_READ_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_DISABLED_CAP = TRUE \n", sizeof ("EFI_READ_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_ENABLED_CAP = TRUE \n", sizeof ("EFI_READ_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_STATUS) {
+ strncat (LocalStr, "EFI_READ_STATUS = TRUE \n", sizeof ("EFI_READ_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_DISABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_ENABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_STATUS = TRUE \n", sizeof ("EFI_WRITE_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_CAP) {
+ strncat (LocalStr, "EFI_LOCK_CAP = TRUE \n", sizeof ("EFI_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_LOCK_STATUS = TRUE \n", sizeof ("EFI_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_STICKY_WRITE) {
+ strncat (LocalStr, "EFI_STICKY_WRITE = TRUE \n", sizeof ("EFI_STICKY_WRITE = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_MEMORY_MAPPED) {
+ strncat (LocalStr, "EFI_MEMORY_MAPPED = TRUE \n", sizeof ("EFI_MEMORY_MAPPED = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_ERASE_POLARITY) {
+ strncat (LocalStr, "EFI_ERASE_POLARITY = 1 \n", sizeof ("EFI_ERASE_POLARITY = 1 \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_CAP) {
+ strncat (LocalStr, "EFI_READ_LOCK_CAP = TRUE \n", sizeof ("EFI_READ_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_CAP) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_CAP = TRUE \n", sizeof ("EFI_WRITE_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_STATUS = TRUE \n", sizeof ("EFI_WRITE_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ //
+ // Alignment
+ //
+ if (Attr & EFI_FVB2_ALIGNMENT_1) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1G = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2G = TRUE \n"));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while write data to %p file. \n", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] BlockMap FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibFvHeaderOptionToStr (
+ IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,
+ IN FILE* InfFile,
+ IN BOOLEAN IsRootFv
+)
+{
+ CHAR8 *LocalStr;
+ CHAR8 *BlockSize;
+ CHAR8 *NumOfBlocks;
+
+ LocalStr = NULL;
+ BlockSize = NULL;
+ NumOfBlocks = NULL;
+
+ if (BlockMap == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // This section will not over 1024 bytes and each line will never over 128 bytes.
+ //
+ LocalStr = (CHAR8 *) malloc (1024);
+ BlockSize = (CHAR8 *) malloc (128);
+ NumOfBlocks = (CHAR8 *) malloc (128);
+
+ if (LocalStr == NULL ||
+ BlockSize == NULL ||
+ NumOfBlocks == NULL) {
+ if (LocalStr != NULL) {
+ free (LocalStr);
+ }
+ if (BlockSize != NULL) {
+ free (BlockSize);
+ }
+ if (NumOfBlocks != NULL) {
+ free (NumOfBlocks);
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', 1024);
+ memset (BlockSize, '\0', 128);
+ memset (NumOfBlocks, '\0', 128);
+
+ strncat (LocalStr, "[options] \n", sizeof("[Options] \n"));
+
+ sprintf (BlockSize, "EFI_BLOCK_SIZE = 0x%x \n", BlockMap->Length);
+ strncat (LocalStr, BlockSize, strlen(BlockSize));
+
+ if (IsRootFv) {
+ sprintf (NumOfBlocks, "EFI_NUM_BLOCKS = 0x%x \n", BlockMap->NumBlocks);
+ strncat (LocalStr, NumOfBlocks, strlen(NumOfBlocks));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ free (LocalStr);
+ free (BlockSize);
+ free (NumOfBlocks);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+ free (BlockSize);
+ free (NumOfBlocks);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] FfsName Ffs file path/name.
+ @param[out] InfFile InfFile contain FV header attribute information
+ @param[in] FirstIn Is the first time call this function? If yes, should create [files] section.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibAddFfsFileToFvInf (
+ IN CHAR8 *FfsName,
+ IN FILE* InfFile,
+ IN BOOLEAN FirstIn
+)
+{
+
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ if (FfsName == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (strlen(FfsName) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ LocalStr = (CHAR8 *) malloc (_MAX_PATH);
+
+ if (LocalStr == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', _MAX_PATH);
+
+ if (FirstIn) {
+ sprintf (LocalStr, "[files] \nEFI_FILE_NAME = %s \n", FfsName);
+ } else {
+ sprintf (LocalStr, "EFI_FILE_NAME = %s \n", FfsName);
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while write data to %p file. \n", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Convert EFI file to PE or TE section
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] Type PE or TE and UI/Version
+ @param[in] OutputFilePath .te or .pe file
+ @param[in] UiString String for generate UI section usage, this parameter is optional
+ unless Type is EFI_SECTION_USER_INTERFACE.
+ @param[in] VerString String for generate Version section usage, this parameter is optional
+ unless Type is EFI_SECTION_VERSION.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibCreateFfsSection (
+ IN CHAR8* InputFilePath, OPTIONAL
+ IN CHAR8* Sections, OPTIONAL
+ IN UINT8 Type,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* UiString, OPTIONAL
+ IN CHAR8* VerString, OPTIONAL
+ IN CHAR8* GuidToolGuid, OPTIONAL
+ IN CHAR8* CompressType OPTIONAL
+ )
+{
+ CHAR8* SystemCommand;
+ SystemCommand = NULL;
+
+ //
+ // Call GenSec tool to generate FFS section.
+ //
+
+ //
+ // -s SectionType.
+ //
+ if (Type != 0) {
+ switch (Type) {
+ //
+ // Process compression section
+ //
+ case EFI_SECTION_COMPRESSION:
+ SystemCommand = malloc (
+ strlen (GENSEC_COMPRESSION) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (CompressType) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_COMPRESSION,
+ mSectionTypeName[Type],
+ CompressType,
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ //
+ // Process GUID defined section
+ //
+ case EFI_SECTION_GUID_DEFINED:
+ SystemCommand = malloc (
+ strlen (GENSEC_GUID) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (GuidToolGuid) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_GUID,
+ mSectionTypeName[Type],
+ GuidToolGuid,
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+ SystemCommand = malloc (
+ strlen (GENSEC_STR) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_STR,
+ mSectionTypeName[Type],
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ case EFI_SECTION_RAW:
+ SystemCommand = malloc (
+ strlen (GENSEC_STR) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_STR,
+ mSectionTypeName[Type],
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ default:
+ printf ("Please specify the section type while call GenSec tool.\n");
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ //
+ // Create Dummy section.
+ //
+ SystemCommand = malloc (
+ strlen (GENSEC_ALIGN) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_ALIGN,
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Encapsulate FFSs to FV
+
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] BlockSize BlockSize is one HEX or DEC format value required by FV image.
+ @param[in] FileTakeSize
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapsulateFfsToFv (
+ IN CHAR8* InfFilePath,
+ IN CHAR8* InputFFSs,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* FvGuidName
+ )
+{
+
+ CHAR8* SystemCommand;
+ CHAR8* FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3";
+
+ SystemCommand = NULL;
+
+ if (OutputFilePath == NULL ||
+ InfFilePath == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InfFilePath != NULL) {
+ if (FvGuidName == NULL) {
+ SystemCommand = malloc (
+ strlen (GENFV_STR) +
+ strlen (InfFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ GENFV_STR,
+ InfFilePath, // -i
+ OutputFilePath // -o
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ } else {
+ //
+ // Have FvGuidName in it.
+ //
+ SystemCommand = malloc (
+ strlen (GENFV_FVGUID) +
+ strlen (InfFilePath) +
+ strlen (OutputFilePath) +
+ strlen (FvGuidName) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ GENFV_FVGUID,
+ InfFilePath, // -i
+ OutputFilePath, // -o
+ FvGuidName // FvNameGuid
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+ }
+
+ if (InputFFSs != NULL) {
+ SystemCommand = malloc (
+ strlen (GENFV_FFS) +
+ strlen (InputFFSs) +
+ strlen (FfsGuid) +
+ strlen (OutputFilePath) +
+ 100
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ GENFV_FFS,
+ InputFFSs, // -f
+ FfsGuid, // -g
+ OutputFilePath // -o
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Convert a GUID to a string.
+
+
+ @param[in] Guid - Pointer to GUID to print.
+
+
+ @return The string after convert.
+
+**/
+CHAR8 *
+LibBfmGuidToStr (
+ IN EFI_GUID *Guid
+)
+{
+ CHAR8 * Buffer;
+
+ Buffer = NULL;
+
+ if (Guid == NULL) {
+ printf ("The guid is NULL while convert guid to string! \n");
+ return NULL;
+ }
+
+ Buffer = (CHAR8 *) malloc (36 + 1);
+
+ if (Buffer == NULL) {
+ printf ("Error while allocate resource! \n");
+ return NULL;
+ }
+ memset (Buffer, '\0', 36 + 1);
+
+ sprintf (
+ Buffer,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ Guid->Data1,
+ Guid->Data2,
+ Guid->Data3,
+ Guid->Data4[0],
+ Guid->Data4[1],
+ Guid->Data4[2],
+ Guid->Data4[3],
+ Guid->Data4[4],
+ Guid->Data4[5],
+ Guid->Data4[6],
+ Guid->Data4[7]
+ );
+
+ return Buffer;
+}
+
+/**
+ Encapsulate an FFS section file to an FFS file.
+
+ @param[in] Type Type is one FV file type defined in PI spec, which is one type of EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,
+ EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,
+ EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION, EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE. This option is required.
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] FileGuid FileGuid is the unique identifier for this FFS file. This option is required.
+ @param[in] Fixed Set fixed attribute in FFS file header to indicate that the file may not be moved from its present location.
+ @param[in] SectionAlign FileAlign specifies FFS file alignment, which only support the following alignment: 8,16,128,512,1K,4K,32K,64K.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapSectionFileToFFS (
+ IN UINT8 Type,
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath,
+ IN EFI_GUID FileGuid,
+ IN BOOLEAN Fixed,
+ IN UINT32 SectionAlign
+ )
+{
+ CHAR8* SystemCommand;
+ CHAR8* GuidStr;
+
+ SystemCommand = NULL;
+ GuidStr = NULL;
+
+ GuidStr = LibBfmGuidToStr(&FileGuid);
+
+ if (NULL == GuidStr) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Type == EFI_FV_FILETYPE_RAW) {
+ SystemCommand = malloc (
+ strlen (GENFFS_STR) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENFFS_STR,
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ } else {
+ //
+ // -t Type
+ // -i InputFilePath
+ // -o OutPutFilePath
+ // -g FileGuid
+ // -x Fixed
+ // -n SectionAlign
+ //
+ if (Fixed) {
+ SystemCommand = malloc (
+ strlen (GENFFS_FIX) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENFFS_FIX,
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ } else {
+ SystemCommand = malloc (
+ strlen (GENFFS_STR) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENFFS_STR,
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ }
+ }
+ free (GuidStr);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibCreateNewFdCopy(
+ IN CHAR8* OldFd,
+ IN CHAR8* NewFd
+)
+{
+ CHAR8* SystemCommand;
+ SystemCommand = NULL;
+
+
+ if (OldFd == NULL ||
+ NewFd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a copy the new file.
+ //
+
+ SystemCommand = malloc (
+ strlen (COPY_STR) +
+ strlen (OldFd) +
+ strlen (NewFd) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ COPY_STR,
+ OldFd,
+ NewFd
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will assemble the filename, directory and extend and return the combined string.
+ Like FileName = file1, Dir = c:\temp extend = txt, the output string will be:
+ c:\temp\file1.txt.
+
+ @param[in]
+ @param[in]
+ @param[in]
+
+ @retrun A string contain all the input information.
+
+**/
+CHAR8 *
+LibFilenameStrExtended (
+ IN CHAR8 *FileName,
+ IN CHAR8 *Dir,
+ IN CHAR8 *Extend
+)
+{
+ CHAR8 *RetStr;
+
+ RetStr = NULL;
+
+ if (FileName == NULL) {
+ return NULL;
+ }
+
+ if (Dir == NULL || Extend == NULL) {
+ return FileName;
+ }
+
+ RetStr = (CHAR8 *) malloc (strlen (FileName) +
+ strlen (Dir) +
+ strlen (Extend) +
+ strlen ("%s%s.%s") +
+ 1);
+ if (NULL == RetStr) {
+ return NULL;
+ }
+
+ memset (RetStr, '\0', (strlen (FileName) + strlen (Dir) + strlen (Extend) + strlen("%s%s.%s") + 1));
+
+ sprintf (RetStr, "%s%s.%s", Dir, FileName, Extend);
+
+ return RetStr;
+}
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+)
+{
+ CHAR8* SystemCommand;
+ SystemCommand = NULL;
+
+
+ if (DirName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (access (DirName, 0) == -1){
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Delete a directory and files in it
+ //
+ SystemCommand = malloc (
+ strlen (RMDIR_STR) +
+ strlen (DirName) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ RMDIR_STR,
+ DirName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a file.
+
+ @param[in] FileName Name of the file need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibBfmDeleteFile(
+ IN CHAR8 *FileName
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+
+ if (FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ //
+ // Delete a file.
+ //
+ SystemCommand = malloc (
+ strlen (DEL_STR) +
+ strlen (FileName) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ DEL_STR,
+ FileName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibBfmFreeFd (
+ FIRMWARE_DEVICE *Fd
+ )
+{
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *TempFv;
+ ENCAP_INFO_DATA *EncapData1;
+ ENCAP_INFO_DATA *EncapData2;
+
+ CurrentFv = NULL;
+ TempFv = NULL;
+ EncapData1 = NULL;
+ EncapData2 = NULL;
+
+ if (Fd == NULL) {
+ return;
+ }
+
+ CurrentFv = Fd->Fv;
+
+ do {
+ TempFv = CurrentFv;
+ CurrentFv = CurrentFv->FvNext;
+
+ if (TempFv->FvHeader != NULL) {
+ free (TempFv->FvHeader);
+ }
+ if (TempFv->FvExtHeader != NULL) {
+ free (TempFv->FvExtHeader);
+ }
+
+ //
+ // Free encapsulate data;
+ //
+ EncapData1 = TempFv->EncapData;
+
+ while (EncapData1 != NULL) {
+
+ EncapData2 = EncapData1;
+ EncapData1 = EncapData1->NextNode;
+
+ if (EncapData2->Data != NULL) {
+ free (EncapData2->Data);
+ }
+ if (EncapData2->FvExtHeader != NULL) {
+ free(EncapData2->FvExtHeader);
+ }
+ free (EncapData2);
+ EncapData2 = NULL;
+ }
+
+ EncapData1 = NULL;
+
+ free (TempFv);
+ TempFv = NULL;
+
+ } while (CurrentFv != NULL);
+
+ CurrentFv = NULL;
+ free (Fd);
+ Fd = NULL;
+
+ return;
+}
+
+/**
+ Generate the compressed section with specific type.
+ Type could be EFI_STANDARD_COMPRESSION or EFI_NOT_COMPRESSED
+
+ @param[in] InputFileName File name of the raw data.
+ @param[in] OutPutFileName File name of the sectioned data.
+ @param[in] CompressionType The compression type.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_ABORTED
+ @return EFI_OUT_OF_RESOURCES
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibGenCompressedSection (
+ CHAR8 *InputFileName,
+ CHAR8 *OutPutFileName,
+ UINT8 CompressionType
+)
+{
+ FILE *UnCompressFile;
+ FILE *CompressedFile;
+ VOID *UnCompressedBuffer;
+ VOID *CompressedBuffer;
+ UINT32 UnCompressedSize;
+ UINT32 CompressedSize;
+ CHAR8 *TempName;
+ CHAR8 *TemDir;
+ CHAR8 *TemString;
+ EFI_STATUS Status;
+
+ UnCompressFile = NULL;
+ CompressedFile = NULL;
+ UnCompressedBuffer = NULL;
+ CompressedBuffer = NULL;
+ TempName = NULL;
+ TemDir = NULL;
+ TemString = NULL;
+ UnCompressedSize = 0;
+ CompressedSize = 0;
+
+ if ( InputFileName == NULL ||
+ OutPutFileName == NULL) {
+ printf ("Error while generate compressed section!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ UnCompressFile = fopen (InputFileName, "rb");
+ if (UnCompressFile == NULL) {
+ printf ("Error while open file %s \n", InputFileName);
+ return EFI_ABORTED;
+ }
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ fclose (UnCompressFile);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ TemString = GenTempFile ();
+ TempName= LibFilenameStrExtended (strrchr(TemString, OS_SEP), TemDir, "comp");
+ free (TemString);
+ TemString = NULL;
+ if (TempName == NULL) {
+ fclose(UnCompressFile);
+ return EFI_ABORTED;
+ }
+
+ CompressedFile = fopen (TempName, "wb+");
+ if (CompressedFile == NULL) {
+ printf ("Error while open file %s \n", TempName);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+ //
+ // Get the original file size;
+ //
+ fseek(UnCompressFile,0,SEEK_SET);
+ fseek(UnCompressFile,0,SEEK_END);
+
+ UnCompressedSize = ftell(UnCompressFile);
+
+ fseek(UnCompressFile,0,SEEK_SET);
+
+ UnCompressedBuffer = malloc (UnCompressedSize);
+
+ if (UnCompressedBuffer == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CompressedBuffer = malloc (UnCompressedSize);
+
+ if (CompressedBuffer == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ free (UnCompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (UnCompressedBuffer, 1, (size_t) UnCompressedSize, UnCompressFile) == (size_t) UnCompressedSize) {
+ CompressedSize = UnCompressedSize;
+
+ Status = EfiCompress ( UnCompressedBuffer,
+ UnCompressedSize,
+ CompressedBuffer,
+ &CompressedSize);
+
+ if (EFI_ERROR(Status)) {
+ printf("Error while do compress operation! \n");
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+
+ if (CompressedSize > UnCompressedSize) {
+ printf("Error while do compress operation! \n");
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error while reading file %s! \n", InputFileName);
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Write the compressed data into output file
+ //
+ if (fwrite (CompressedBuffer, 1, (size_t) CompressedSize, CompressedFile) != (size_t) CompressedSize) {
+ printf ("Error while writing %s file. \n", OutPutFileName);
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+
+ //
+ // Call GenSec tool to generate the compressed section.
+ //
+ LibCreateFfsSection(TempName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, "PI_STD");
+ free (TempName);
+ TempName = NULL;
+
+ } else if (CompressionType == EFI_NOT_COMPRESSED) {
+
+ LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, "PI_NONE");
+
+ } else {
+ printf ("Error while generate compressed section, unknown compression type! \n");
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+)
+{
+ EFI_GUID Guid;
+ STRING_LIST *Tool;
+ GUID_SEC_TOOL_ENTRY *FirstGuidTool;
+ GUID_SEC_TOOL_ENTRY *LastGuidTool;
+ GUID_SEC_TOOL_ENTRY *NewGuidTool;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
+ "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
+ "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
+ "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
+ "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
+ };
+
+
+ Tool = NULL;
+ FirstGuidTool = NULL;
+ LastGuidTool = NULL;
+ NewGuidTool = NULL;
+ Index = 0;
+
+ for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
+ Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
+ if ((Tool != NULL) &&
+ (Tool->Count == 3)
+ ) {
+ Status = StringToGuid (Tool->Strings[0], &Guid);
+ if (!EFI_ERROR (Status)) {
+ NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
+ if (NewGuidTool != NULL) {
+ memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
+ NewGuidTool->Name = CloneString(Tool->Strings[1]);
+ NewGuidTool->Path = CloneString(Tool->Strings[2]);
+ NewGuidTool->Next = NULL;
+ } else {
+ printf ( "Fail to allocate memory. \n");
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ }
+ return NULL;
+ }
+ if (FirstGuidTool == NULL) {
+ FirstGuidTool = NewGuidTool;
+ } else {
+ LastGuidTool->Next = NewGuidTool;
+ }
+ LastGuidTool = NewGuidTool;
+ }
+ } else {
+ fprintf (stdout, "Error");
+ }
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ Tool = NULL;
+ }
+ }
+ return FirstGuidTool;
+}
+
+EFI_STATUS
+LibLocateFvViaFvId (
+ IN FIRMWARE_DEVICE *FdData,
+ IN CHAR8 *FvId,
+ IN OUT FV_INFORMATION **FvInFd
+)
+{
+ UINT8 FvIndex1;
+ UINT8 FvIndex2;
+ BOOLEAN FvFoundFlag;
+
+ FvIndex1 = 0;
+ FvIndex2 = 0;
+ FvFoundFlag = FALSE;
+
+ if (FdData == NULL || FvId == NULL) {
+ printf ( "Error while find FV in FD. \n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FvInFd = FdData->Fv;
+
+ FvIndex1 = (UINT8) atoi (FvId + 2);
+
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvName) != NULL) {
+ FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+ if ((FvIndex2 <= FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 >= FvIndex1)) {
+ FvFoundFlag = TRUE;
+ break;
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ }
+
+ //
+ // The specified FV id has issue, can not find the FV in FD.
+ //
+ if (!FvFoundFlag) {
+ printf ( "Error while find FV in FD. \n");
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+EFI_STATUS
+LibPatchResetVectorAndFitTableData (
+IN CHAR8 *OutputFileName,
+IN PATCH_DATA_PAD_FFS *PatchData
+)
+{
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ UINT8 *Buffer;
+ UINT32 Count;
+
+
+ Count = 0;
+ Buffer = NULL;
+ NewFvFile = NULL;
+
+ if (OutputFileName == NULL || PatchData == NULL) {
+ return EFI_ABORTED;
+ }
+
+ NewFvFile = fopen (OutputFileName, "rb+");
+ if (NewFvFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile, 0, SEEK_SET);
+ fseek(NewFvFile, 0, SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+
+ do {
+
+ //
+ // The FV length should larger than Offset.
+ //
+ if (NewFvLength < PatchData->Offset) {
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,PatchData->Offset,SEEK_SET);
+
+ Buffer = (UINT8 *) malloc (PatchData->Length);
+
+ if (Buffer == NULL) {
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) PatchData->Length, NewFvFile) != (size_t) PatchData->Length) {
+ fclose (NewFvFile);
+ free(Buffer);
+ return EFI_ABORTED;
+ }
+
+ //
+ // The area used to patch data should be filled by 0xff.
+ //
+ for (Count = 0; Count< PatchData->Length; Count++) {
+ if (Buffer[Count] != 0xff){
+ fclose (NewFvFile);
+ free(Buffer);
+ return EFI_ABORTED;
+ }
+ }
+
+ free(Buffer);
+
+ fseek(NewFvFile,PatchData->Offset,SEEK_SET);
+
+ if (fwrite (PatchData->Data, 1, (size_t) PatchData->Length, NewFvFile) != (size_t) PatchData->Length) {
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ PatchData = PatchData->NextNode;
+ } while (PatchData != NULL);
+
+ fclose (NewFvFile);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ OUT CHAR8 **OutputFile
+)
+{
+ EFI_STATUS Status;
+ UINT32 ParentType;
+ UINT8 ParentLevel;
+ UINT32 Type;
+ UINT8 Level;
+ CHAR8 *InfFileName;
+ FILE *InfFile;
+ ENCAP_INFO_DATA *LocalEncapData;
+ BOOLEAN FfsFoundFlag;
+ UINT32 Index;
+ CHAR8 *ExtractionTool;
+ BOOLEAN IsLastLevelFfs;
+ BOOLEAN IsLeafFlagIgnore;
+ BOOLEAN FirstInFlag;
+ CHAR8 *InputFileName;
+ CHAR8 *OutputFileName;
+ CHAR8 *FvGuidName;
+
+ Index = 0;
+ ParentType = 0;
+ ParentLevel = 0;
+ Type = 0;
+ Level = 0;
+ FfsFoundFlag = FALSE;
+ ExtractionTool = NULL;
+ InputFileName = NULL;
+ OutputFileName = NULL;
+ IsLastLevelFfs = TRUE;
+ IsLeafFlagIgnore = FALSE;
+ FirstInFlag = TRUE;
+ FvGuidName = NULL;
+
+ //
+ // Encapsulate from the lowest FFS file level.
+ //
+ LocalEncapData = FvInFd->EncapData;
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+
+ //
+ // Get FV Name GUID
+ //
+
+ while (LocalEncapData != NULL) {
+ //
+ // Has changed.
+ //
+ if (LocalEncapData->Level > Level) {
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_FFS) {
+ ParentLevel = Level;
+ ParentType = Type;
+ }
+
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+ }
+
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ } else {
+ break;
+ }
+ }
+
+ do {
+ switch (ParentType) {
+ case BFM_ENCAP_TREE_FV:
+
+ //
+ // Generate FV.inf attributes.
+ //
+ InfFileName = LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "inf");
+
+ InfFile = fopen (InfFileName, "wt+");
+
+ if (InfFile == NULL) {
+ printf ("Could not open inf file %s to store FV information. \n", InfFileName);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ //
+ // FV GUID Name memory allocation
+ //
+ FvGuidName = (CHAR8 *) malloc (255);
+
+ if (FvGuidName == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ fclose (InfFile);
+ return EFI_ABORTED;
+ }
+
+ memset(FvGuidName, '\0', 255);
+
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+ LocalEncapData->FvExtHeader->FvName.Data1,
+ LocalEncapData->FvExtHeader->FvName.Data2,
+ LocalEncapData->FvExtHeader->FvName.Data3,
+ LocalEncapData->FvExtHeader->FvName.Data4[0],
+ LocalEncapData->FvExtHeader->FvName.Data4[1],
+ LocalEncapData->FvExtHeader->FvName.Data4[2],
+ LocalEncapData->FvExtHeader->FvName.Data4[3],
+ LocalEncapData->FvExtHeader->FvName.Data4[4],
+ LocalEncapData->FvExtHeader->FvName.Data4[5],
+ LocalEncapData->FvExtHeader->FvName.Data4[6],
+ LocalEncapData->FvExtHeader->FvName.Data4[7]
+ );
+
+ } else {
+ FvGuidName = NULL;
+ }
+
+
+ if (ParentLevel == 1) {
+ Status = LibFvHeaderOptionToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->BlockMap, InfFile, TRUE);
+ } else {
+ Status = LibFvHeaderOptionToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->BlockMap, InfFile, FALSE);
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ printf ("Generate FV INF file [Options] section failed.\n");
+ fclose (InfFile);
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ return Status;
+ }
+
+ Status = LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->Attributes, InfFile);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Generate FV header attribute failed.\n");
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ fclose (InfFile);
+ return Status;
+ }
+ if (LocalEncapData->FvExtHeader != NULL) {
+ Status = LibGenExtFile(LocalEncapData->FvExtHeader, InfFile);
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ if (EFI_ERROR(Status)) {
+ printf("Generate FV EXT header failed.\n");
+ fclose (InfFile);
+ return Status;
+ }
+ FvGuidName = NULL;
+ }
+
+ //
+ // Found FFSs from Fv structure.
+ //
+ FfsFoundFlag = FALSE;
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+
+ //
+ // For the last level FFS, the level below FFSs we should not care the IsLeaf Flag.
+ //
+ if (IsLastLevelFfs) {
+ IsLeafFlagIgnore = TRUE;
+ } else {
+ IsLeafFlagIgnore = FvInFd->FfsAttuibutes[Index].IsLeaf;
+ }
+
+ if (FvInFd->FfsAttuibutes[Index].Level >= ParentLevel + 1 && IsLeafFlagIgnore) {
+ if (FirstInFlag) {
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, TRUE);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section. \n");
+ fclose (InfFile);
+ return Status;
+ }
+
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ FirstInFlag = FALSE;
+ } else {
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section. \n");
+ fclose (InfFile);
+ return Status;
+ }
+
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ }
+ FfsFoundFlag = TRUE;
+ }
+ //
+ // Also add the sub FV
+ //
+ if (FvInFd->FfsAttuibutes[Index].Level - 1 == ParentLevel+ 1) {
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel + 2) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_GUIDED_SECTION) {
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section.\n");
+ fclose (InfFile);
+ return Status;
+ }
+
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ }
+
+ }
+ }
+
+ IsLastLevelFfs = FALSE;
+ FirstInFlag = TRUE;
+ if (!FfsFoundFlag) {
+ Status = LibAddFfsFileToFvInf (OutputFileName, InfFile, TRUE);
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section.\n");
+ fclose (InfFile);
+ return Status;
+ }
+ }
+ /*
+ if (OutputFileName != NULL && FfsFoundFlag) {
+ Status = LibAddFfsFileToFvInf (OutputFileName, InfFile, FALSE);
+
+ if (EFI_ERROR (Status)) {
+ //Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ return Status;
+ }
+ }
+ */
+ //
+ // Create FV
+ //
+ fclose (InfFile);
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "FV");
+ Status = LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileName, FvGuidName);
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Patch FIT Table Data or reset vector data if exist.
+ //
+ if ((FvInFd->PatchData != NULL) && (1 == ParentLevel)) {
+ Status = LibPatchResetVectorAndFitTableData(OutputFileName, FvInFd->PatchData);
+ if (EFI_ERROR (Status)) {
+ printf ("Error while patch FIT Table Data or reset vector data. \n");
+ return Status;
+ }
+ }
+
+ break;
+ case BFM_ENCAP_TREE_FFS:
+ if (OutputFileName != NULL) {
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "ffs");
+
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, ((EFI_FFS_FILE_HEADER *)LocalEncapData->Data)->Name, FALSE, 0);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FFS file. \n");
+ return Status;
+ }
+ }
+ break;
+ case BFM_ENCAP_TREE_GUIDED_SECTION:
+ //
+ // Create the guided section original data, do compress operation.
+ //
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "compressed");
+
+ //
+ // Use the guided section header guid to find out compress application name.
+ //
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ (EFI_GUID *)LocalEncapData->Data
+ );
+
+ Status = LibCreateGuidedSectionOriginalData (InputFileName, ExtractionTool, OutputFileName);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while compress guided data. \n");
+ return Status;
+ }
+
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "guided");
+
+ Status = LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_GUID_DEFINED, OutputFileName, NULL, NULL, LibBfmGuidToStr((EFI_GUID *)LocalEncapData->Data), NULL);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate guided section. \n");
+ return Status;
+ }
+
+ break;
+ case BFM_ENCAP_TREE_COMPRESS_SECTION:
+ if (OutputFileName != NULL) {
+ InputFileName = OutputFileName;
+
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "comsec");
+
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ Status = LibGenCompressedSection (InputFileName, OutputFileName, *(UINT8 *)(LocalEncapData->Data));
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate compressed section. \n");
+ return Status;
+ }
+ }
+ break;
+ case BFM_ENCAP_TREE_FV_SECTION:
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ Status = LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV section. \n");
+ return Status;
+ }
+
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ //
+ // Make it alignment.
+ //
+ Status = LibCreateFfsSection(InputFileName, NULL, 0, OutputFileName, NULL, NULL, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV section. \n");
+ return Status;
+ }
+
+ break;
+ default:
+ printf("Don't know how to encapsulate the FD file! \n");
+ return EFI_ABORTED;
+ }
+
+
+ //
+ // Find next level and encapsulate type
+ //
+ ParentLevel -= 1;
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ ParentType = LocalEncapData->Type;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ } while (ParentLevel != 0);
+
+
+ *OutputFile = OutputFileName;
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+LibLocateBfv(
+ IN FIRMWARE_DEVICE *FdData,
+ IN OUT CHAR8 **FvId,
+ IN OUT FV_INFORMATION **FvInFd
+)
+{
+ UINT8 FvIndex1;
+ UINT8 FvIndex2;
+ BOOLEAN FvFoundFlag;
+
+ FvIndex1 = 0;
+ FvIndex2 = 0;
+ FvFoundFlag = FALSE;
+
+ if (FdData == NULL || FvId == NULL || FvInFd == NULL) {
+ return EFI_ABORTED;
+ }
+
+ *FvId = (*FvInFd)->FvName;
+
+ FvIndex1 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+ *FvInFd = FdData->Fv;
+
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvName) != NULL) {
+ FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+ if ((FvIndex2 <= FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 >= FvIndex1)) {
+ FvFoundFlag = TRUE;
+ break;
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ }
+
+ //
+ // The specified FV id has issue, can not find the FV in FD.
+ //
+ if (!FvFoundFlag) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get the length of a file.
+
+ @param[in] FileName The name of a file.
+
+ @retval The length of file.
+
+**/
+UINT64
+GetFileSize (
+ IN CHAR8 *FileName
+)
+{
+ FILE* File;
+ UINT64 Length;
+
+ File = NULL;
+
+ if (FileName == NULL) {
+ return 0;
+ }
+ File = fopen(FileName, "r");
+
+ if (File == NULL) {
+ return 0;
+ }
+ fseek(File, 0L, SEEK_END);
+ Length = ftell(File);
+ fclose(File);
+
+ return Length;
+}
+
+/**
+
+ Get the length of BFV PAD file.
+
+ @retval The length of PAD file.
+
+**/
+UINT32
+GetBfvPadSize (
+ VOID
+)
+{
+ return PadSizeOfBfv;
+}
+
diff --git a/BaseTools/Source/C/BfmLib/BinFileManager.c b/BaseTools/Source/C/BfmLib/BinFileManager.c
new file mode 100644
index 0000000000..8c8b67bd37
--- /dev/null
+++ b/BaseTools/Source/C/BfmLib/BinFileManager.c
@@ -0,0 +1,1024 @@
+/** @file
+
+ The main entry of BFM tool.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinFileManager.h"
+
+BOOLEAN mFvGuidIsSet = FALSE;
+EFI_GUID mFvNameGuid = {0};
+CHAR8* mFvNameGuidString = NULL;
+CHAR8* mGuidToolDefinition = "GuidToolDefinitionConf.ini";
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+
+
+/**
+ Search the config file from the path list.
+
+ Split the path from env PATH, and then search the cofig
+ file from these paths. The priority is from left to
+ right of PATH string. When met the first Config file, it
+ will break and return the pointer to the full file name.
+
+ @param PathList the pointer to the path list.
+ @param FileName the pointer to the file name.
+
+ @retval The pointer to the file name.
+ @return NULL An error occurred.
+**/
+CHAR8 *
+SearchConfigFromPathList (
+ IN CHAR8 *PathList,
+ IN CHAR8 *FileName
+)
+{
+ CHAR8 *CurDir;
+ CHAR8 *FileNamePath;
+
+ CurDir = NULL;
+ FileNamePath = NULL;
+#ifndef __GNUC__
+ CurDir = strtok (PathList,";");
+#else
+ CurDir = strtok (PathList,":");
+#endif
+ while (CurDir != NULL) {
+ FileNamePath = (char *)calloc(
+ strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
+ sizeof(char)
+ );
+ if (FileNamePath == NULL) {
+ return NULL;
+ }
+ sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
+ if (access (FileNamePath, 0) != -1) {
+ return FileNamePath;
+ }
+#ifndef __GNUC__
+ CurDir = strtok(NULL, ";");
+#else
+ CurDir = strtok(NULL, ":");
+#endif
+ free (FileNamePath);
+ FileNamePath = NULL;
+ }
+ return NULL;
+}
+
+/**
+
+ Show the FD image layout information. Only display the modules with UI name.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FvName The FV ID in the FD file;
+ @param[in] ViewFlag Is this call for view or other operate(add/del/replace)
+ @param[in] FdData The Fd data structure store the FD information.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageView (
+ IN CHAR8* FdInName,
+ IN CHAR8* FvName,
+ IN BOOLEAN ViewFlag,
+ IN FIRMWARE_DEVICE **FdData
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *LocalFdData;
+ FV_INFORMATION *CurrentFv;
+ FILE *InputFile;
+ UINT32 FvSize;
+ UINTN BytesRead;
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage;
+ UINT32 FfsCount;
+ UINT8 FvCount;
+ UINT8 LastFvNumber;
+
+ LocalFdData = NULL;
+ CurrentFv = NULL;
+ FvImage = NULL;
+ FvSize = 0;
+ BytesRead = 0;
+ FfsCount = 0;
+ FvCount = 0;
+ LastFvNumber = 0;
+
+ //
+ // Check the FD file name/path.
+ //
+ if (FdInName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open the file containing the FV
+ //
+ InputFile = fopen (FdInName, "rb");
+ if (InputFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = LibFindFvInFd (InputFile, &LocalFdData);
+
+ if (EFI_ERROR(Status)) {
+ fclose (InputFile);
+ return EFI_ABORTED;
+ }
+
+ CurrentFv = LocalFdData->Fv;
+
+ do {
+
+ memset (CurrentFv->FvName, '\0', _MAX_PATH);
+
+ if (LastFvNumber == 0) {
+ sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
+ } else {
+ sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
+ }
+
+ //
+ // Determine size of FV
+ //
+ if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return EFI_ABORTED;
+ }
+
+ Status = LibGetFvSize(InputFile, &FvSize);
+ if (EFI_ERROR (Status)) {
+ fclose (InputFile);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET);
+
+ FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize);
+
+ if (FvImage == NULL) {
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return EFI_ABORTED;
+ }
+
+ BytesRead = fread (FvImage, 1, FvSize, InputFile);
+ if ((unsigned int) BytesRead != FvSize) {
+ free (FvImage);
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Collect FV information each by each.
+ //
+ Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &FfsCount, ViewFlag, FALSE);
+ free (FvImage);
+ FvImage = NULL;
+ if (EFI_ERROR (Status)) {
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return Status;
+ }
+ FvCount = CurrentFv->FvLevel;
+ LastFvNumber = LastFvNumber+FvCount;
+
+ FfsCount = 0;
+
+ CurrentFv = CurrentFv->FvNext;
+
+ } while (CurrentFv != NULL);
+
+ if (!ViewFlag) {
+ *FdData = LocalFdData;
+ } else {
+ LibBfmFreeFd( LocalFdData);
+ }
+
+ fclose (InputFile);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add an FFS file into a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] NewFile The name of the file add in;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageAdd (
+ IN CHAR8* FdInName,
+ IN CHAR8* NewFile,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ UINT64 NewFfsLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT8 FvEncapLevel;
+ UINT8 NewAddedFfsLevel;
+ BOOLEAN FfsLevelFoundFlag;
+ CHAR8 *OutputFileName;
+ CHAR8 *FvId;
+ BOOLEAN FirstInFlag;
+ BOOLEAN FvGuidExisted;
+
+ NewFvLength = 0;
+ FvEncapLevel = 0;
+ NewAddedFfsLevel = 0;
+
+ FfsLevelFoundFlag = FALSE;
+ FirstInFlag = TRUE;
+ FdData = NULL;
+ FvInFd = NULL;
+ LocalEncapData = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ LocalEncapDataTemp = NULL;
+ OutputFileName = NULL;
+ FvId = NULL;
+ FvGuidExisted = FALSE;
+
+ //
+ // Get the size of ffs file to be inserted.
+ //
+ NewFfsLength = GetFileSize(NewFile);
+
+ Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while parse %s FD image.\n", FdInName);
+ return Status;
+ }
+ //
+ // Check the FvGuid whether exists or not when the BIOS hasn't default setting.
+ // If the FV image with -g GUID can't be found, the storage is still saved into the BFV and report warning message.
+ //
+ FvInFd = FdData->Fv;
+ do {
+ if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+ FvGuidExisted = TRUE;
+ break;
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+ if (mFvGuidIsSet && !FvGuidExisted) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ //
+ // Iterate to write FFS to each BFV.
+ //
+ FvInFd = FdData->Fv;
+ do {
+ if ((FvGuidExisted && mFvGuidIsSet && FvInFd->IsInputFvFlag) || ((!FvGuidExisted || (!mFvGuidIsSet)) && FvInFd->IsBfvFlag)) {
+
+ Status = LibLocateBfv (FdData, &FvId, &FvInFd);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while locate BFV from FD.\n");
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ //
+ // Determine the new added ffs file level in the FV.
+ //
+ LocalEncapData = FvInFd->EncapData;
+
+ while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
+ if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
+ //
+ // Found the FFS level in this FV.
+ //
+ LocalEncapDataTemp = LocalEncapData;
+ while (LocalEncapDataTemp != NULL) {
+ if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
+ NewAddedFfsLevel = LocalEncapDataTemp->Level;
+ FfsLevelFoundFlag = TRUE;
+ break;
+ }
+ if (LocalEncapDataTemp->NextNode != NULL) {
+ LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+ } else {
+ break;
+ }
+ }
+ }
+ FvEncapLevel ++;
+ }
+
+ if (LocalEncapData->NextNode == NULL) {
+ break;
+ } else {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+
+ //
+ // Add the new file into FV.
+ //
+ FvInFd->FfsNumbers += 1;
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ printf ("The NewFile name is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName[_MAX_PATH - 1] = 0;
+ FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level = NewAddedFfsLevel;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n",(unsigned long) GetBfvPadSize (), (unsigned long long)NewFfsLength);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ if (FirstInFlag) {
+ //
+ // Write New Fv file into the NewFd file.
+ //
+ Status = LibCreateNewFdCopy (FdInName, FdOutName);
+ if (EFI_ERROR (Status)) {
+ printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+ FirstInFlag = FALSE;
+ }
+
+ NewFdFile = fopen (FdOutName, "rb+");
+ if (NewFdFile == NULL) {
+ printf("Error while create FD file %s. \n", FdOutName);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ NewFvFile = fopen (OutputFileName, "rb+");
+
+ if (NewFvFile == NULL) {
+ printf("Error while create Fv file %s. \n", OutputFileName);
+ fclose(NewFdFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+
+ fseek(NewFvFile,0,SEEK_SET);
+
+ Buffer = malloc ((size_t)NewFvLength);
+
+ if (Buffer == NULL) {
+ printf ("Error while allocate resource! \n");
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ printf("Error while reading Fv file %s. \n", OutputFileName);
+ free (Buffer);
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
+ printf("Error while writing FD file %s. \n", FdOutName);
+ fclose(NewFdFile);
+ fclose (NewFvFile);
+ free (Buffer);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
+ free (Buffer);
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ free (Buffer);
+ Buffer = NULL;
+
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+
+ LibBfmFreeFd(FdData);
+
+ if (TemDir == NULL) {
+ if (mFvGuidIsSet) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
+ } else {
+ printf ("BFV image can't be found.\n");
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ Status = LibRmDir (TemDir);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while remove temporary directory. \n");
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Replace an FFS file into a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] NewFile The name of the file add in;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageReplace (
+ IN CHAR8* FdInName,
+ IN CHAR8* NewFile,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ UINT64 NewFfsLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ CHAR8 *OutputFileName;
+ CHAR8 *FvId;
+ BOOLEAN FirstInFlag;
+ UINT32 Index;
+ BOOLEAN FvToBeUpdate;
+ BOOLEAN FdIsUpdate;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ UINT8 FvEncapLevel;
+ UINT8 NewAddedFfsLevel;
+ BOOLEAN FfsLevelFoundFlag;
+ EFI_GUID EfiNewAddToBfvGuid;
+ FILE* FfsFile;
+ UINTN BytesRead;
+ BOOLEAN ReplaceSameFv;
+ BOOLEAN FvGuidExisted;
+
+ NewFvLength = 0;
+ FdIsUpdate = FALSE;
+ FirstInFlag = TRUE;
+ FdData = NULL;
+ FvInFd = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ OutputFileName = NULL;
+ FvId = NULL;
+ FfsFile = NULL;
+ BytesRead = 0;
+ ReplaceSameFv = FALSE;
+ FvGuidExisted = FALSE;
+
+ //
+ // Get the size of ffs file to be inserted.
+ //
+ NewFfsLength = GetFileSize(NewFile);
+ //
+ // Get FFS GUID
+ //
+ FfsFile = fopen (NewFile, "rb");
+ if (FfsFile == NULL) {
+ printf ("Error while read %s.\n", NewFile);
+ return EFI_ABORTED;
+ }
+ fseek (FfsFile, 0, SEEK_SET);
+ BytesRead = fread (&EfiNewAddToBfvGuid, 1, sizeof(EFI_GUID), FfsFile);
+ fclose (FfsFile);
+ if (BytesRead != sizeof(EFI_GUID)) {
+ printf ("Error while read the GUID from %s.\n", NewFile);
+ return EFI_ABORTED;
+ }
+ Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while parse %s FD image.\n", FdInName);
+ return Status;
+ }
+
+ //
+ // Check the FvGuid whether exists or not when the BIOS has default setting.
+ // 1. No option means the storage is saved into the same FV image.
+ // 2. The FV image with -g GUID can't be found. The storage is still saved into the same FV image and report warning message.
+ //
+ if (!mFvGuidIsSet) {
+ ReplaceSameFv = TRUE;
+ }
+ FvInFd = FdData->Fv;
+ do {
+ if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+ FvGuidExisted = TRUE;
+ break;
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+ if (mFvGuidIsSet && !FvGuidExisted) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
+ ReplaceSameFv = TRUE;
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ //
+ // Interate to insert or replace default setting to Fv
+ //
+ FvInFd = FdData->Fv;
+ do {
+ FvToBeUpdate = FALSE;
+ if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+ FvToBeUpdate = TRUE;
+ }
+
+ Status = LibLocateBfv (FdData, &FvId, &FvInFd);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while locate BFV from FD.\n");
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ Index = 0;
+ while (Index <= FvInFd->FfsNumbers) {
+ //
+ // Locate the multi-platform ffs in Fv and then replace or delete it.
+ //
+ if (!CompareGuid(&FvInFd->FfsHeader[Index].Name, &EfiNewAddToBfvGuid)) {
+ if (ReplaceSameFv) {
+ FvToBeUpdate = TRUE;
+ }
+ break;
+ }
+ Index ++;
+ }
+
+ if (FvToBeUpdate || (Index <= FvInFd->FfsNumbers)) {
+ if (FvToBeUpdate) {
+ FdIsUpdate = TRUE;
+ if (Index <= FvInFd->FfsNumbers) {
+ //
+ // Override original default data by New File
+ //
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ printf ("The NewFile name is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
+ } else {
+ FfsLevelFoundFlag = FALSE;
+ FvEncapLevel = 0;
+ NewAddedFfsLevel = 0;
+ //
+ // Determine the new added ffs file level in the FV.
+ //
+ LocalEncapData = FvInFd->EncapData;
+
+ while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
+ if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
+ //
+ // Found the FFS level in this FV.
+ //
+ LocalEncapDataTemp = LocalEncapData;
+ while (LocalEncapDataTemp != NULL) {
+ if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
+ NewAddedFfsLevel = LocalEncapDataTemp->Level;
+ FfsLevelFoundFlag = TRUE;
+ break;
+ }
+ if (LocalEncapDataTemp->NextNode != NULL) {
+ LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+ } else {
+ break;
+ }
+ }
+ }
+ FvEncapLevel ++;
+ }
+
+ if (LocalEncapData->NextNode == NULL) {
+ break;
+ } else {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+
+ //
+ // Add the new file into FV.
+ //
+ FvInFd->FfsNumbers += 1;
+ memcpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH);
+ FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level = NewAddedFfsLevel;
+ }
+ } else {
+ //
+ // Remove original default data from FV.
+ //
+ FvInFd->FfsAttuibutes[Index].FfsName[0] = '\0';
+ }
+
+ if (TemDir == NULL) {
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR)+ strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+
+ Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n", (unsigned long) GetBfvPadSize (), (unsigned long long) NewFfsLength);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ if (FirstInFlag) {
+ //
+ // Write New Fv file into the NewFd file.
+ //
+ Status = LibCreateNewFdCopy (FdInName, FdOutName);
+ if (EFI_ERROR (Status)) {
+ printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+ FirstInFlag = FALSE;
+ }
+
+ NewFdFile = fopen (FdOutName, "rb+");
+ if (NewFdFile == NULL) {
+ printf("Error while create FD file %s. \n", FdOutName);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ NewFvFile = fopen (OutputFileName, "rb+");
+
+ if (NewFvFile == NULL) {
+ printf("Error while create Fv file %s. \n", OutputFileName);
+ LibBfmFreeFd(FdData);
+ fclose (NewFdFile);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+
+ fseek(NewFvFile,0,SEEK_SET);
+
+ Buffer = malloc ((size_t)NewFvLength);
+
+ if (Buffer == NULL) {
+ LibBfmFreeFd(FdData);
+ fclose (NewFdFile);
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ printf("Error while read Fv file %s. \n", OutputFileName);
+ LibBfmFreeFd(FdData);
+ free (Buffer);
+ fclose (NewFdFile);
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
+ printf("Error while write FD file %s. \n", FdOutName);
+ fclose(NewFdFile);
+ fclose (NewFvFile);
+ LibBfmFreeFd(FdData);
+ free (Buffer);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
+ free (Buffer);
+ LibBfmFreeFd(FdData);
+ fclose (NewFdFile);
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ free (Buffer);
+ Buffer = NULL;
+
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+ LibBfmFreeFd(FdData);
+
+ if (TemDir == NULL || !FdIsUpdate) {
+ if (mFvGuidIsSet) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
+ } else {
+ printf ("BFV image can't be found.\n");
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ Status = LibRmDir (TemDir);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while remove temporary directory. \n");
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ The main entry of BFM tool.
+
+**/
+int main(
+ int Argc,
+ char *Argv[]
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ CHAR8 *InFilePath;
+ CHAR8 FullGuidToolDefinition[_MAX_PATH];
+ CHAR8 *FileName;
+ UINTN FileNameIndex;
+ CHAR8 *PathList;
+ UINTN EnvLen;
+ CHAR8 *NewPathList;
+
+ FdData = NULL;
+ PathList = NULL;
+ NewPathList = NULL;
+ EnvLen = 0;
+
+ if (Argc <= 1) {
+ return -1;
+ }
+ FileName = Argv[0];
+ //
+ // Save, skip filename arg
+ //
+ Argc--;
+ Argv++;
+
+ if ((stricmp(Argv[0], "-v") == 0)) {
+ //
+ // Check the revison of BfmLib
+ // BfmLib -v
+ //
+ printf("%s\n", __BUILD_VERSION);
+ return 1;
+
+ }
+ //
+ // Workaroud: the first call to this function
+ // returns a file name ends with dot
+ //
+#ifndef __GNUC__
+ tmpnam (NULL);
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ close(Fdtmp);
+#endif
+ //
+ // Get the same path with the application itself
+ //
+ if (strlen (FileName) > _MAX_PATH - 1) {
+ Error (NULL, 0, 2000, "Parameter: Input file name is too long", NULL);
+ return -1;
+ }
+ strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1);
+ FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+ FileNameIndex = strlen (FullGuidToolDefinition);
+ while (FileNameIndex != 0) {
+ FileNameIndex --;
+ if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+ FullGuidToolDefinition[FileNameIndex] = 0;
+ break;
+ }
+ }
+ //
+ // Build the path list for Config file scan. The priority is below.
+ // 1. Scan the current path
+ // 2. Scan the same path with the application itself
+ // 3. Scan the current %PATH% of OS environment
+ // 4. Use the build-in default configuration
+ //
+ PathList = getenv("PATH");
+ if (PathList == NULL) {
+ Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
+ return -1;
+ }
+ EnvLen = strlen(PathList);
+ NewPathList = (char *)calloc(
+ strlen (".")
+ + strlen (";")
+ + strlen (FullGuidToolDefinition)
+ + strlen (";")
+ + EnvLen
+ + 1,
+ sizeof(char)
+ );
+ if (NewPathList == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ PathList = NULL;
+ free (PathList);
+ return -1;
+ }
+#ifndef __GNUC__
+ sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList);
+#else
+ sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList);
+#endif
+
+ PathList = NULL;
+ free (PathList);
+ //
+ // Load Guid Tools definition
+ //
+ InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
+ free (NewPathList);
+ if (InFilePath != NULL) {
+ printf ("\nThe Guid Tool Definition of BfmLib comes from the '%s'. \n", InFilePath);
+ mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+ free (InFilePath);
+ } else {
+ //
+ // Use the pre-defined standard guided tools.
+ //
+ printf ("\nThe Guid Tool Definition of BfmLib comes from the build-in default configuration. \n");
+ mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
+ }
+
+ //
+ // BfmLib -e FdName.Fd
+ //
+ if ((stricmp(Argv[0], "-e") == 0)) {
+
+ if (Argc != 2) {
+ return -1;
+ }
+ //
+ // Extract FFS files.
+ //
+ Status = BfmImageView (Argv[1], NULL, FALSE, &FdData);
+
+ if (EFI_ERROR (Status)) {
+ return -1;
+ }
+
+ if (FdData == NULL) {
+ return -1;
+ }
+
+ LibBfmFreeFd(FdData);
+
+ } else if ((stricmp(Argv[0], "-i") == 0)) {
+ //
+ // Insert FFS files to BFV
+ // BfmLib -i InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
+ //
+ if (Argc == 6) {
+ mFvGuidIsSet = TRUE;
+ mFvNameGuidString = Argv[5];
+ StringToGuid (Argv[5], &mFvNameGuid);
+ Argc -= 2;
+ }
+ if (Argc != 4) {
+ return -1;
+ }
+ Status = BfmImageAdd(Argv[1], Argv[2], Argv[3]);
+
+ if (EFI_ERROR (Status)) {
+ return -1;
+ }
+
+ } else if ((stricmp(Argv[0], "-r") == 0)) {
+ //
+ // Replace FFS files in BFV
+ // BfmLib -r InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
+ //
+ if (Argc == 6) {
+ mFvGuidIsSet = TRUE;
+ mFvNameGuidString = Argv[5];
+ StringToGuid (Argv[5], &mFvNameGuid);
+ Argc -= 2;
+ }
+ if (Argc != 4) {
+ return -1;
+ }
+ Status = BfmImageReplace (Argv[1], Argv[2], Argv[3]);
+
+ if (EFI_ERROR (Status)) {
+ return -1;
+ }
+
+ } else {
+ //
+ // Invalid parameter.
+ //
+ return -1;
+ }
+
+ return 1;
+}
+
diff --git a/BaseTools/BinWrappers/PosixLike/BfmLib b/BaseTools/BinWrappers/PosixLike/BfmLib
new file mode 100755
index 0000000000..a244ecc095
--- /dev/null
+++ b/BaseTools/BinWrappers/PosixLike/BfmLib
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
+dir=$(dirname "$full_cmd")
+cmd=${full_cmd##*/}
+
+if [ -n "$WORKSPACE" ] && [ -e "$WORKSPACE/Conf/BaseToolsCBinaries" ]
+then
+ exec "$WORKSPACE/Conf/BaseToolsCBinaries/$cmd"
+elif [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/Source/C" ]
+then
+ if [ ! -e "$EDK_TOOLS_PATH/Source/C/bin/$cmd" ]
+ then
+ echo "BaseTools C Tool binary was not found ($cmd)"
+ echo "You may need to run:"
+ echo " make -C $EDK_TOOLS_PATH/Source/C"
+ else
+ exec "$EDK_TOOLS_PATH/Source/C/bin/$cmd" "$@"
+ fi
+elif [ -e "$dir/../../Source/C/bin/$cmd" ]
+then
+ exec "$dir/../../Source/C/bin/$cmd" "$@"
+else
+ echo "Unable to find the real '$cmd' to run"
+ echo "This message was printed by"
+ echo " $0"
+ exit 127
+fi
+
diff --git a/BaseTools/Source/C/BfmLib/BinFileManager.h b/BaseTools/Source/C/BfmLib/BinFileManager.h
new file mode 100644
index 0000000000..ea27f2e8f2
--- /dev/null
+++ b/BaseTools/Source/C/BfmLib/BinFileManager.h
@@ -0,0 +1,439 @@
+/** @file
+
+ The header of BinFileManager.c.
+
+Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BIN_FILE_MANAGER_
+#define _BIN_FILE_MANAGER_
+
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FvLib.h>
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Common/PiFirmwareFile.h>
+
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "Compress.h"
+#include "Decompress.h"
+#include "ParseInf.h"
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+#ifdef __GNUC__
+#define OS_SEP '/'
+#define OS_SEP_STR "/"
+#define COPY_STR "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR "rm -r \"%s\" > /dev/null"
+#define DEL_STR "rm \"%s\" > /dev/null"
+#else
+#define OS_SEP '\\'
+#define OS_SEP_STR "\\"
+#define COPY_STR "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR "del \"%s\" > NUL"
+#endif
+
+#define TEMP_DIR_NAME "Temp"
+#define UTILITY_NAME "Binary File Manager (BFM)"
+#define UTILITY_SHORT_NAME "BFM"
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 1
+#define MAX_BASENAME_LEN 60 // not good to HardCode, but let's be reasonable
+#define EFI_SECTION_ERROR EFIERR (100)
+//
+// The maximum number of Pad file guid entries.
+//
+#define MAX_NUMBER_OF_PAD_FILE_GUIDS 1024
+
+//
+// The maximum number of block map entries supported by the library
+//
+#define MAX_NUMBER_OF_FV_BLOCKS 100
+
+
+//
+// The maximum number of sections in an FFS file.
+//
+#define MAX_NUMBER_OF_SECTION_IN_FFS 100
+
+//
+// The maximum number of files in the FV supported by the library
+//
+#define MAX_NUMBER_OF_FILES_IN_FV 1000
+#define MAX_NUMBER_OF_FILES_IN_CAP 1000
+
+
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE is only used by DXE driver.
+///
+#define EFI_DEP_BEFORE 0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER is only used by DXE driver.
+///
+#define EFI_DEP_AFTER 0x01
+
+#define EFI_DEP_PUSH 0x02
+#define EFI_DEP_AND 0x03
+#define EFI_DEP_OR 0x04
+#define EFI_DEP_NOT 0x05
+#define EFI_DEP_TRUE 0x06
+#define EFI_DEP_FALSE 0x07
+#define EFI_DEP_END 0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR 0x09
+
+//
+// INF file strings
+//
+#define OPTIONS_SECTION_STRING "[options]"
+#define ATTRIBUTES_SECTION_STRING "[attributes]"
+#define FILES_SECTION_STRING "[files]"
+#define FV_BASE_ADDRESS_STRING "[FV_BASE_ADDRESS]"
+
+//
+// Options section
+//
+#define EFI_FV_BASE_ADDRESS_STRING "EFI_BASE_ADDRESS"
+#define EFI_FV_FILE_NAME_STRING "EFI_FILE_NAME"
+#define EFI_NUM_BLOCKS_STRING "EFI_NUM_BLOCKS"
+#define EFI_BLOCK_SIZE_STRING "EFI_BLOCK_SIZE"
+#define EFI_GUID_STRING "EFI_GUID"
+#define EFI_FV_FILESYSTEMGUID_STRING "EFI_FV_GUID"
+#define EFI_FV_NAMEGUID_STRING "EFI_FVNAME_GUID"
+#define EFI_CAPSULE_GUID_STRING "EFI_CAPSULE_GUID"
+#define EFI_CAPSULE_HEADER_SIZE_STRING "EFI_CAPSULE_HEADER_SIZE"
+#define EFI_CAPSULE_FLAGS_STRING "EFI_CAPSULE_FLAGS"
+#define EFI_CAPSULE_VERSION_STRING "EFI_CAPSULE_VERSION"
+
+#define EFI_FV_TOTAL_SIZE_STRING "EFI_FV_TOTAL_SIZE"
+#define EFI_FV_TAKEN_SIZE_STRING "EFI_FV_TAKEN_SIZE"
+#define EFI_FV_SPACE_SIZE_STRING "EFI_FV_SPACE_SIZE"
+
+
+typedef UINT32 BFM_ENCAP_TYPE;
+
+#define MAX_LEVEL_IN_FV_FILE 32
+
+//
+// Types of BFM_ENCAP_TREENODE_TYPE
+//
+#define BFM_ENCAP_TREE_FV 0x1
+#define BFM_ENCAP_TREE_FFS 0x2
+#define BFM_ENCAP_TREE_GUIDED_SECTION 0x3
+#define BFM_ENCAP_TREE_COMPRESS_SECTION 0x4
+#define BFM_ENCAP_TREE_FV_SECTION 0x5
+
+extern EFI_HANDLE mParsedGuidedSectionTools;
+extern BOOLEAN mFvGuidIsSet;
+extern EFI_GUID mFvNameGuid;
+
+//
+// Structure to keep a list of GUID-To-BaseNames
+//
+typedef struct _GUID_TO_BASENAME {
+ struct _GUID_TO_BASENAME *Next;
+ INT8 Guid[PRINTED_GUID_BUFFER_SIZE];
+ INT8 BaseName[MAX_BASENAME_LEN];
+} GUID_TO_BASENAME;
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+ EFI_GUID Guid;
+ CHAR8* Name;
+ CHAR8* Path;
+ struct _GUID_SEC_TOOL_ENTRY *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+//
+// Private data types
+//
+//
+// Component information
+//
+typedef struct {
+ UINTN Size;
+ CHAR8 ComponentName[_MAX_PATH];
+} COMPONENT_INFO;
+
+typedef struct {
+ CHAR8 FfsName[_MAX_PATH];
+
+ //
+ // UI Name for this FFS file, if has.
+ //
+ CHAR16 UiName[_MAX_PATH];
+
+ //
+ // Total section number in this FFS.
+ //
+ UINT32 TotalSectionNum;
+
+ //
+ // Describe the position of the FFS file.
+ //
+ UINT8 Level;
+ //
+ // If this FFS has no encapsulate section, this flag will set to True.
+ //
+ BOOLEAN IsLeaf;
+ //
+ // Section type for each section in FFS.
+ //
+ EFI_SECTION_TYPE SectionType[MAX_NUMBER_OF_SECTION_IN_FFS];
+
+}FFS_ATTRIBUTES;
+
+
+typedef struct __ENCAP_INFO_DATA{
+ //
+ // Now Level
+ //
+ UINT8 Level;
+
+ //
+ // Encapsulate type.
+ //
+ BFM_ENCAP_TYPE Type;
+
+ //
+ // Data, if it's FV, should be FV header.
+ //
+ VOID *Data;
+
+ //
+ // if FV ExtHeaderOffset not to zero, should also have FvExtHeader information
+ //
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+
+ //
+ // Next node.
+ //
+ struct __ENCAP_INFO_DATA *NextNode;
+}ENCAP_INFO_DATA;
+
+
+//
+// Contain Offset and Data for PAD FFS contain reset vector or FIT data.
+//
+typedef struct _PATCH_DATA_PAD_FFS {
+ //
+ // The offset of data relative to FV start address;
+ //
+ UINT32 Offset;
+ //
+ // Data
+ //
+ VOID *Data;
+ //
+ // Length of Data
+ //
+ UINT32 Length;
+ //
+ // Next node.
+ //
+ struct _PATCH_DATA_PAD_FFS *NextNode;
+} PATCH_DATA_PAD_FFS;
+
+
+//
+// FV and capsule information holder
+//
+typedef struct _FV_INFOMATION{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+ UINT32 ImageAddress;
+ UINT32 FfsNumbers;
+ CHAR8 FvName[_MAX_PATH];
+ EFI_FV_BLOCK_MAP_ENTRY FvBlocks[MAX_NUMBER_OF_FV_BLOCKS];
+ FFS_ATTRIBUTES FfsAttuibutes[MAX_NUMBER_OF_FILES_IN_FV];
+ EFI_FFS_FILE_HEADER2 FfsHeader[MAX_NUMBER_OF_FILES_IN_FV];
+ struct _FV_INFOMATION *FvNext;
+ ENCAP_INFO_DATA *EncapData;
+ UINT8 FvLevel;
+ PATCH_DATA_PAD_FFS *PatchData;
+ BOOLEAN IsBfvFlag;
+ BOOLEAN IsInputFvFlag;
+
+} FV_INFORMATION;
+
+typedef struct _FIRMWARE_DEVICE {
+ ///
+ /// Size of FD file
+ ///
+ UINT32 Size;
+ FV_INFORMATION *Fv;
+} FIRMWARE_DEVICE;
+
+VOID
+Usage (
+ VOID
+);
+
+
+CHAR8 *
+GenTempFile (
+ VOID
+);
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+);
+
+/**
+
+ Add function description
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN UINT32 *FfsCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ );
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ );
+
+ /**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ );
+
+EFI_STATUS
+LibCreateNewFdCopy(
+ IN CHAR8* OldFd,
+ IN CHAR8* NewFd
+ );
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+ );
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibBfmFreeFd (
+ FIRMWARE_DEVICE *Fd
+);
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+);
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ OUT CHAR8 **OutputFile
+);
+
+EFI_STATUS
+LibLocateBfv(
+ IN FIRMWARE_DEVICE *FdData,
+ IN OUT CHAR8 **FvId,
+ IN OUT FV_INFORMATION **FvInFd
+);
+
+/**
+
+ Get the length of a file.
+
+ @param[in] FileName The name of a file.
+
+ @retval The length of file.
+
+**/
+UINT64
+GetFileSize (
+ IN CHAR8 *FileName
+);
+
+/**
+
+ Get the length of BFV PAD file.
+
+ @retval The length of PAD file.
+
+**/
+UINT32
+GetBfvPadSize (
+ VOID
+);
+#endif
diff --git a/BaseTools/Source/C/BfmLib/GNUmakefile b/BaseTools/Source/C/BfmLib/GNUmakefile
new file mode 100644
index 0000000000..a2c2f41a1b
--- /dev/null
+++ b/BaseTools/Source/C/BfmLib/GNUmakefile
@@ -0,0 +1,15 @@
+## @file
+# GNU/Linux makefile for 'BfmLib' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= ..
+
+APPNAME = BfmLib
+
+LIBS = -lCommon
+
+OBJECTS = BinFileManager.o BfmLib.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
diff --git a/BaseTools/Source/C/BfmLib/Makefile b/BaseTools/Source/C/BfmLib/Makefile
new file mode 100644
index 0000000000..2b7483b10f
--- /dev/null
+++ b/BaseTools/Source/C/BfmLib/Makefile
@@ -0,0 +1,17 @@
+## @file
+#
+# Windows makefile for 'BfmLib' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent#
+##
+!INCLUDE ..\Makefiles\ms.common
+
+APPNAME = BfmLib
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = BinFileManager.obj BfmLib.obj
+
+!INCLUDE ..\Makefiles\ms.app
+
diff --git a/BaseTools/Source/C/GNUmakefile b/BaseTools/Source/C/GNUmakefile
index 37bcce519c..824f0306e6 100644
--- a/BaseTools/Source/C/GNUmakefile
+++ b/BaseTools/Source/C/GNUmakefile
@@ -47,6 +47,7 @@ VFRAUTOGEN = VfrCompile/VfrLexer.h
APPLICATIONS = \
BrotliCompress \
VfrCompile \
+ BfmLib \
EfiRom \
GenFfs \
GenFv \
diff --git a/BaseTools/Source/C/Makefile b/BaseTools/Source/C/Makefile
index 217fc2b91d..a6d39eb864 100644
--- a/BaseTools/Source/C/Makefile
+++ b/BaseTools/Source/C/Makefile
@@ -12,6 +12,7 @@ LIBRARIES = Common
APPLICATIONS = \
VfrCompile \
BrotliCompress \
+ BfmLib \
EfiRom \
GenCrc32 \
GenFfs \
--
2.13.0.windows.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Patch v3 2/3] BaseTools: Add a tool FCE
2019-07-01 11:27 [Patch v3 0/3] BaseTools: Move FCE & FMMT tools to edk2 repo Liming Gao
2019-07-01 11:27 ` [Patch v3 1/3] BaseTools: Add a tool BfmLib Liming Gao
@ 2019-07-01 11:27 ` Liming Gao
2019-07-01 11:27 ` [Patch v3 3/3] BaseTools: Add a tool FMMT Liming Gao
2 siblings, 0 replies; 4+ messages in thread
From: Liming Gao @ 2019-07-01 11:27 UTC (permalink / raw)
To: devel; +Cc: Shenglei Zhang, Bob Feng
From: Shenglei Zhang <shenglei.zhang@intel.com>
FCE is a tool to retrieve and change HII configuration data in
Firmware Device(*.fd) files.
https://bugzilla.tianocore.org/show_bug.cgi?id=1848
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
Reviewed-by: Bob Feng <bob.c.feng@intel.com>
---
BaseTools/Source/C/FCE/BinaryCreate.c | 216 +
BaseTools/Source/C/FCE/BinaryParse.c | 1326 +++++
BaseTools/Source/C/FCE/Common.c | 2183 ++++++++
BaseTools/Source/C/FCE/Expression.c | 2367 +++++++++
BaseTools/Source/C/FCE/Fce.c | 6449 +++++++++++++++++++++++
BaseTools/Source/C/FCE/IfrParse.c | 4836 +++++++++++++++++
BaseTools/Source/C/FCE/MonotonicBasedVariable.c | 874 +++
BaseTools/Source/C/FCE/TimeBasedVariable.c | 878 +++
BaseTools/Source/C/FCE/Variable.c | 1091 ++++
BaseTools/BinWrappers/PosixLike/FCE | 29 +
BaseTools/Source/C/FCE/BinaryCreate.h | 157 +
BaseTools/Source/C/FCE/BinaryParse.h | 187 +
BaseTools/Source/C/FCE/Common.h | 999 ++++
BaseTools/Source/C/FCE/Fce.h | 447 ++
BaseTools/Source/C/FCE/GNUmakefile | 55 +
BaseTools/Source/C/FCE/IfrParse.h | 789 +++
BaseTools/Source/C/FCE/Makefile | 19 +
BaseTools/Source/C/FCE/MonotonicBasedVariable.h | 162 +
BaseTools/Source/C/FCE/TimeBasedVariable.h | 166 +
BaseTools/Source/C/FCE/Variable.h | 154 +
BaseTools/Source/C/FCE/VariableCommon.h | 55 +
BaseTools/Source/C/GNUmakefile | 3 +-
BaseTools/Source/C/Makefile | 3 +-
23 files changed, 23443 insertions(+), 2 deletions(-)
create mode 100644 BaseTools/Source/C/FCE/BinaryCreate.c
create mode 100644 BaseTools/Source/C/FCE/BinaryParse.c
create mode 100644 BaseTools/Source/C/FCE/Common.c
create mode 100644 BaseTools/Source/C/FCE/Expression.c
create mode 100644 BaseTools/Source/C/FCE/Fce.c
create mode 100644 BaseTools/Source/C/FCE/IfrParse.c
create mode 100644 BaseTools/Source/C/FCE/MonotonicBasedVariable.c
create mode 100644 BaseTools/Source/C/FCE/TimeBasedVariable.c
create mode 100644 BaseTools/Source/C/FCE/Variable.c
create mode 100755 BaseTools/BinWrappers/PosixLike/FCE
create mode 100644 BaseTools/Source/C/FCE/BinaryCreate.h
create mode 100644 BaseTools/Source/C/FCE/BinaryParse.h
create mode 100644 BaseTools/Source/C/FCE/Common.h
create mode 100644 BaseTools/Source/C/FCE/Fce.h
create mode 100644 BaseTools/Source/C/FCE/GNUmakefile
create mode 100644 BaseTools/Source/C/FCE/IfrParse.h
create mode 100644 BaseTools/Source/C/FCE/Makefile
create mode 100644 BaseTools/Source/C/FCE/MonotonicBasedVariable.h
create mode 100644 BaseTools/Source/C/FCE/TimeBasedVariable.h
create mode 100644 BaseTools/Source/C/FCE/Variable.h
create mode 100644 BaseTools/Source/C/FCE/VariableCommon.h
diff --git a/BaseTools/Source/C/FCE/BinaryCreate.c b/BaseTools/Source/C/FCE/BinaryCreate.c
new file mode 100644
index 0000000000..2f36bc2ef3
--- /dev/null
+++ b/BaseTools/Source/C/FCE/BinaryCreate.c
@@ -0,0 +1,216 @@
+/** @file
+
+ The API to create the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinaryCreate.h"
+#ifndef __GNUC__
+#define GENSEC_RAW "GenSec -s %s \"%s\" -o \"%s\" > NUL"
+#else
+#define GENSEC_RAW "GenSec -s %s \"%s\" -o \"%s\" > /dev/null"
+#endif
+
+//
+// The guid is to for FFS of BFV.
+//
+EFI_GUID gEfiFfsBfvForMultiPlatformGuid = EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID;
+EFI_GUID gEfiFfsBfvForMultiPlatformGuid2 = EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID2;
+
+/**
+ Convert a GUID to a string.
+
+ @param[in] Guid Pointer to GUID to print.
+
+ @return The string after convert.
+**/
+static
+CHAR8 *
+LibBfmGuidToStr (
+ IN EFI_GUID *Guid
+)
+{
+ CHAR8 * Buffer;
+
+ Buffer = NULL;
+
+ if (Guid == NULL) {
+ return NULL;
+ }
+
+ Buffer = (CHAR8 *) malloc (36 + 1);
+
+ if (Buffer == NULL) {
+ return NULL;
+ }
+ memset (Buffer, '\0', 36 + 1);
+
+ sprintf (
+ Buffer,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ Guid->Data1,
+ Guid->Data2,
+ Guid->Data3,
+ Guid->Data4[0],
+ Guid->Data4[1],
+ Guid->Data4[2],
+ Guid->Data4[3],
+ Guid->Data4[4],
+ Guid->Data4[5],
+ Guid->Data4[6],
+ Guid->Data4[7]
+ );
+
+ return Buffer;
+}
+
+/**
+ Create the Ras section in FFS
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] OutputFilePath .te or .pe file
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawSection (
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath
+ )
+{
+ INT32 ReturnValue;
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+ SystemCommand = malloc (
+ strlen (GENSEC_RAW) +
+ strlen ("EFI_SECTION_RAW") +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_RAW,
+ "EFI_SECTION_RAW",
+ InputFilePath,
+ OutputFilePath
+ );
+ ReturnValue = system (SystemCommand);
+ free(SystemCommand);
+
+ if (ReturnValue != 0) {
+ printf ("Error. Call GenSec failed.\n");
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Create the Ras type of FFS
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] OutputFilePath .te or .pe file
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawFfs (
+ IN CHAR8** InputFilePaths,
+ IN CHAR8* OutputFilePath,
+ IN BOOLEAN SizeOptimized
+ )
+{
+ INT32 ReturnValue;
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ CHAR8* GuidStr;
+ CHAR8* FilePathFormatStr;
+ CHAR8* FilePathStr;
+ UINT32 Index;
+ UINT32 StrLen;
+ UINT32 Size;
+
+ SystemCommand = NULL;
+ GuidStr = NULL;
+ FilePathStr = NULL;
+ StrLen = 0;
+
+ FilePathFormatStr = " -i \"";
+
+ for (Index = 0; InputFilePaths[Index] != NULL; Index++) {
+ Size = strlen (FilePathFormatStr) + strlen (InputFilePaths[Index]) + 2; // 2 menas "" "
+ if (FilePathStr == NULL) {
+ FilePathStr = malloc (Size);
+ if (NULL == FilePathStr) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ FilePathStr = realloc (FilePathStr, StrLen + Size);
+ if (NULL == FilePathStr) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ memset (FilePathStr + StrLen, ' ', Size);
+ memcpy (FilePathStr + StrLen, FilePathFormatStr, strlen(FilePathFormatStr));
+ memcpy(FilePathStr + StrLen + strlen(FilePathFormatStr), InputFilePaths[Index], strlen(InputFilePaths[Index]));
+ StrLen += Size;
+ *(FilePathStr + StrLen - 2) = '\"';
+ }
+ if (FilePathStr == NULL) {
+ return EFI_ABORTED;
+ }
+ *(FilePathStr + StrLen - 1)= '\0';
+
+
+ if (SizeOptimized) {
+ GuidStr = LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid2);
+ } else {
+ GuidStr = LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid);
+ }
+ if (NULL == GuidStr) {
+ free (FilePathStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SystemCommandFormatString = "GenFfs -t %s %s -g %s -o \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen ("EFI_FV_FILETYPE_FREEFORM") +
+ strlen (FilePathStr) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ free (FilePathStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFfs -t %s %s -g %s -o \"%s\"",
+ "EFI_FV_FILETYPE_FREEFORM",// -t
+ FilePathStr, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+ ReturnValue = system (SystemCommand);
+ free(SystemCommand);
+ free (FilePathStr);
+ free (GuidStr);
+
+ if (ReturnValue != 0) {
+ printf ("Error. Call GenFfs failed.\n");
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
diff --git a/BaseTools/Source/C/FCE/BinaryParse.c b/BaseTools/Source/C/FCE/BinaryParse.c
new file mode 100644
index 0000000000..e9f8ee6826
--- /dev/null
+++ b/BaseTools/Source/C/FCE/BinaryParse.c
@@ -0,0 +1,1326 @@
+/** @file
+
+ The API to parse the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GNUC__
+#include "windows.h"
+#else
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#endif
+#include "BinaryParse.h"
+#include "BinaryCreate.h"
+#include "VariableCommon.h"
+#include "FirmwareVolumeBufferLib.h"
+
+extern G_EFI_FD_INFO gEfiFdInfo;
+extern EFI_HANDLE mParsedGuidedSectionTools;
+extern CHAR8 mInputFdName[MAX_FILENAME_LEN];
+
+//
+// The Guid to sign the position of Vfr and Uni array in FV
+//
+EFI_GUID gVfrArrayAttractGuid = EFI_VFR_ATTRACT_GUID;
+EFI_GUID gUniStrArrayAttractGuid = EFI_UNI_STR_ATTRACT_GUID;
+EFI_GUID gEfiSystemNvDataFvGuid = EFI_SYSTEM_NVDATA_FV_GUID;
+EFI_GUID gEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
+
+/**
+ Converts a three byte length value into a UINT32.
+
+ @param ThreeByteLength Pointer to the first of the 3 byte length.
+
+ @retval Length Size of the section
+
+**/
+static
+UINT32
+Get3ByteLength (
+ IN UINT8 *ThreeByteLength
+ )
+{
+ UINT32 Length;
+
+ Length = 0;
+
+ if (ThreeByteLength == NULL) {
+ return 0;
+ }
+
+ Length = *((UINT32 *) ThreeByteLength);
+ Length = Length & 0x00FFFFFF;
+
+ return Length;
+}
+
+/**
+ Generate the unique template filename.
+**/
+CHAR8 *
+GenTempFile (
+ VOID
+ )
+{
+ CHAR8 *TemString;
+ TemString = NULL;
+#ifndef __GNUC__
+ TemString = CloneString (tmpnam (NULL));
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ TemString = CloneString(tmp);
+ close(Fdtmp);
+#endif
+ return TemString;
+}
+
+/**
+ Check whether exist the same Ifr FFS. If not existed, return TRUE.
+
+ @param[in] FfsImage The pointer to the binary.
+ @param[in] FileSize The size of binary.
+
+ @return The string after convert.
+**/
+static
+BOOLEAN
+NotExistSameFfsIfr (
+ IN VOID *FfsImage
+)
+{
+ UINT32 Index;
+
+ Index = 0;
+
+ while (gEfiFdInfo.FfsArray[Index] != NULL) {
+ if (memcmp (gEfiFdInfo.FfsArray[Index], FfsImage, sizeof (EFI_GUID)) == 0) {
+ return FALSE;
+ }
+ Index++;
+ }
+ return TRUE;
+}
+
+/**
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param ActualSize The size.
+ @param Alignment The desired alignment.
+
+ @retval The Occupied length
+
+**/
+static
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ )
+{
+ UINT32 OccupiedSize;
+
+ OccupiedSize = ActualSize;
+ while ((OccupiedSize & (Alignment - 1)) != 0) {
+ OccupiedSize++;
+ }
+
+ return OccupiedSize;
+}
+
+
+/**
+ Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS.
+
+ @param SectionBuffer The section base address
+ @param BufferLength The length of FFS.
+ @param EfiBufferHeader The structure dual pointer to the efi informations
+
+ @retval EFI_SUCCESS The application exited normally.
+ @retval EFI_ABORTED An error occurred.
+
+**/
+EFI_STATUS
+ParseSection (
+ IN BOOLEAN IsFfsOrEfi,
+ IN OUT UINT8 *SectionBuffer,
+ IN UINT32 BufferLength,
+ IN OUT EFI_SECTION_STRUCT **EfiBufferHeader
+ )
+{
+ UINT32 ParsedLength;
+ EFI_SECTION_TYPE Type;
+ UINT8 *Ptr;
+ UINT32 SectionLength;
+ UINT8 *CompressedBuffer;
+ UINT32 CompressedLength;
+ UINT8 *UncompressedBuffer;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+ DECOMPRESS_FUNCTION DecompressFunction;
+ GETINFO_FUNCTION GetInfoFunction;
+ UINT32 ScratchSize;
+ UINT8 *ScratchBuffer;
+ EFI_STATUS Status;
+ UINT32 DstSize;
+ CHAR8 *ExtractionTool;
+ CHAR8 *ToolInputFile;
+ CHAR8 *ToolOutputFile;
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ UINT8 *ToolOutputBuffer;
+ UINT32 ToolOutputLength;
+ BOOLEAN HasDepexSection;
+
+ Ptr = NULL;
+ SectionLength = 0;
+ CompressedBuffer = NULL;
+ CompressedLength = 0;
+ UncompressedBuffer = NULL;
+ UncompressedLength = 0;
+ CompressionType = 0;
+ ScratchSize = 0;
+ ScratchBuffer = NULL;
+ Status = EFI_SUCCESS;
+ DstSize = 0;
+ ExtractionTool = NULL;
+ ToolInputFile = NULL;
+ ToolOutputFile = NULL;
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+
+ //
+ // Jump the FFS header
+ //
+ if (IsFfsOrEfi) {
+ SectionBuffer = SectionBuffer + sizeof (EFI_FFS_FILE_HEADER);
+ BufferLength = BufferLength - sizeof (EFI_FFS_FILE_HEADER);
+ }
+ ParsedLength = 0;
+ HasDepexSection = FALSE;
+ ExtractionTool = NULL;
+ ToolOutputLength = 0;
+ ToolOutputBuffer = NULL;
+
+ (*EfiBufferHeader)->Length = BufferLength;
+
+ while (ParsedLength < BufferLength) {
+ Ptr = SectionBuffer + ParsedLength;
+
+ SectionLength = Get3ByteLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if ((SectionLength == 0xffffff) && (Type == 0xff)) {
+ ParsedLength += 4;
+ continue;
+ }
+
+ switch (Type) {
+
+ case EFI_SECTION_PE32:
+ case EFI_SECTION_TE:
+ //
+ //Got the correct address
+ //
+ (*EfiBufferHeader)->BufferBase = (UINTN)(Ptr + sizeof (EFI_COMMON_SECTION_HEADER));
+ return EFI_SUCCESS;
+
+ case EFI_SECTION_RAW:
+ case EFI_SECTION_PIC:
+ break;
+
+ case EFI_SECTION_USER_INTERFACE:
+ HasDepexSection = FALSE;
+ break;
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+ case EFI_SECTION_COMPATIBILITY16:
+ case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+ break;
+
+ case EFI_SECTION_PEI_DEPEX:
+ case EFI_SECTION_DXE_DEPEX:
+ case EFI_SECTION_SMM_DEPEX:
+ HasDepexSection = TRUE;
+ break;
+
+ case EFI_SECTION_VERSION:
+ break;
+ case EFI_SECTION_COMPRESSION:
+ UncompressedBuffer = NULL;
+ CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION);
+ UncompressedLength = ((EFI_COMPRESSION_SECTION *) Ptr)->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION *) Ptr)->CompressionType;
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+ if (CompressedLength != UncompressedLength) {
+ Error (
+ NULL,
+ 0,
+ 0,
+ "file is not compressed, but the compressed length does not match the uncompressed length",
+ NULL
+ );
+ return EFI_ABORTED;
+ }
+
+ UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION);
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ GetInfoFunction = EfiGetInfo;
+ DecompressFunction = EfiDecompress;
+ CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION);
+
+ Status = GetInfoFunction (
+ CompressedBuffer,
+ CompressedLength,
+ &DstSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error getting compression info from compression section", NULL);
+ return EFI_ABORTED;
+ }
+
+ if (DstSize != UncompressedLength) {
+ Error (NULL, 0, 0003, "compression error in the compression section", NULL);
+ return EFI_ABORTED;
+ }
+
+ ScratchBuffer = malloc (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_ABORTED;
+ }
+ UncompressedBuffer = malloc (UncompressedLength);
+ if (UncompressedBuffer == NULL) {
+ free (ScratchBuffer);
+ return EFI_ABORTED;
+ }
+ memset (UncompressedBuffer, 0, UncompressedLength);
+
+ Status = DecompressFunction (
+ CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ ScratchBuffer,
+ ScratchSize
+ );
+ free (ScratchBuffer);
+ if (Status != EFI_SUCCESS) {
+ Error (NULL, 0, 0003, "decompress failed", NULL);
+ free (UncompressedBuffer);
+ return EFI_ABORTED;
+ }
+ } else {
+ Error (NULL, 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType);
+ return EFI_ABORTED;
+ }
+
+ Status = ParseSection (FALSE, UncompressedBuffer, UncompressedLength, EfiBufferHeader);
+ if (Status != EFI_SUCCESS) {
+ Error (NULL, 0, 0003, "failed to parse section", NULL);
+ free (UncompressedBuffer);
+ UncompressedBuffer = NULL;
+ } else {
+ return EFI_SUCCESS;
+ }
+ //
+ // Store the allocate memory address for UncompressedBuffer
+ //
+ if (UncompressedBuffer != NULL) {
+ (*EfiBufferHeader)->UncompressedBuffer[(*EfiBufferHeader)->UnCompressIndex] = (UINTN) UncompressedBuffer;
+ (*EfiBufferHeader)->UnCompressIndex = (*EfiBufferHeader)->UnCompressIndex + 1;
+ }
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ //
+ // Decompress failed, and then check for CRC32 sections which we can handle internally if needed.
+ // Maybe this section is no-compressed.
+ //
+ if (!CompareGuid (
+ &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid,
+ &gEfiCrc32GuidedSectionExtractionProtocolGuid
+ )) {
+ //
+ // CRC32 guided section
+ //
+ Status = ParseSection (
+ FALSE,
+ SectionBuffer + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+ BufferLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+ EfiBufferHeader
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of CRC32 GUIDED section failed", NULL);
+ return EFI_ABORTED;
+ } else {
+ return EFI_SUCCESS;
+ }
+ } else {
+ ExtractionTool = LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid
+ );
+
+ if (ExtractionTool != NULL) {
+ ToolInputFile = GenTempFile ();
+ ToolOutputFile = GenTempFile ();
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "%s -d -o \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) \
+ + strlen (ExtractionTool) \
+ + strlen (ToolInputFile) \
+ + strlen (ToolOutputFile) \
+ + 1
+ );
+ if (SystemCommand == NULL) {
+ free (ExtractionTool);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "%s -d -o \"%s\" \"%s\"",
+ ExtractionTool,
+ ToolOutputFile,
+ ToolInputFile
+ );
+ free (ExtractionTool);
+
+ Status = PutFileImage (
+ ToolInputFile,
+ (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset
+ );
+
+ if (HasDepexSection) {
+ HasDepexSection = FALSE;
+ }
+
+ system (SystemCommand);
+ remove (ToolInputFile);
+ free (ToolInputFile);
+ ToolInputFile = NULL;
+ free (SystemCommand);
+ SystemCommand = NULL;
+
+ if (EFI_ERROR (Status)) {
+ Error ("FCE", 0, 0004, "unable to decoded GUIDED section", NULL);
+ free (ToolOutputFile);
+ return EFI_ABORTED;
+ }
+
+ Status = GetFileImage (
+ ToolOutputFile,
+ (CHAR8 **)&ToolOutputBuffer,
+ &ToolOutputLength
+ );
+ remove (ToolOutputFile);
+ free (ToolOutputFile);
+ ToolOutputFile = NULL;
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ Status = ParseSection (
+ FALSE,
+ ToolOutputBuffer,
+ ToolOutputLength,
+ EfiBufferHeader
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_ABORTED;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+
+ return EFI_ABORTED;
+}
+
+static
+BOOLEAN
+GetNextOffset (
+ IN UINT8 *Data,
+ IN EFI_GUID *Guid,
+ IN UINTN Len,
+ IN OUT UINTN *Offset
+ )
+{
+ UINTN NextOffset;
+ if (*Offset >= Len || Len - *Offset <= sizeof (EFI_GUID)) {
+ return FALSE;
+ }
+
+ for (NextOffset = *Offset; NextOffset < Len - sizeof (EFI_GUID); NextOffset++) {
+ if (CompareGuid(Guid, (EFI_GUID*)(Data + NextOffset)) == 0) {
+ *Offset = NextOffset + sizeof(EFI_GUID);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Get the address by Guid.
+
+ Parse the FFS image, and find the GUID address.There may be some Guids matching the
+ searched Guid.
+
+ @param Fv the Pointer to the image.
+ @param Guid The Guid need to find.
+ @param Offset The dual Pointer to the offset.
+ @param NumOfMatchGuid The number of matching Guid offset.
+
+ @retval EFI_SUCCESS The Search was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+GetAddressByGuid (
+ IN VOID *Fv,
+ IN EFI_GUID *Guid,
+ IN UINTN Len,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchGuid
+ )
+{
+ VOID *LocalFv;
+ UINT8 Flag;
+
+ EFI_RAW_SECTION* Section;
+ UINT8 *RawData;
+ VOID* SectionStart;
+ UINTN NextOffset;
+ UINTN Key;
+ UINTN TotalSectionsSize;
+ UINTN SecLen;
+ UINTN SecHdr;
+ EFI_STATUS Status;
+
+ if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) || Len == 0 ){
+ return EFI_ABORTED;
+ }
+
+ LocalFv = Fv;
+ Flag = 0;
+ Section = NULL;
+ Key = 0;
+
+ if (NumOfMatchGuid != NULL) {
+ *NumOfMatchGuid = 0;
+ }
+
+ SectionStart = (VOID*)((UINTN)LocalFv + FvBufGetFfsHeaderSize(LocalFv));
+ TotalSectionsSize = Len - FvBufGetFfsHeaderSize(LocalFv);
+ while (TRUE) {
+ Status = FvBufFindNextSection (
+ SectionStart,
+ TotalSectionsSize,
+ &Key,
+ (VOID **)&Section
+ );
+ if (Section == NULL || EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (EFI_SECTION_RAW == Section->Type) {
+ if ((*(UINT32 *)Section->Size & 0xffffff) == 0xffffff) {
+ SecLen = ((EFI_RAW_SECTION2 *)Section)->ExtendedSize;
+ SecHdr = sizeof(EFI_RAW_SECTION2);
+ } else {
+ SecLen = *(UINT32 *)Section->Size & 0xffffff;
+ SecHdr = sizeof(EFI_RAW_SECTION);
+ }
+ if (SecLen <= SecHdr || SecLen - SecHdr < sizeof(EFI_GUID)) {
+ continue;
+ }
+ RawData = (UINT8 *)Section + SecHdr;
+ NextOffset = 0;
+ while (GetNextOffset(RawData, Guid, SecLen - SecHdr, &NextOffset)) {
+ Flag = 1;
+ if ((NumOfMatchGuid != NULL) && (Offset != NULL)) {
+ if (*NumOfMatchGuid == 0) {
+ *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ if (*Offset == NULL) {
+ return EFI_ABORTED;
+ }
+ memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ }
+ *(*Offset + *NumOfMatchGuid) = NextOffset + (RawData - (UINT8 *)Fv);
+ (*NumOfMatchGuid)++;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if( Flag == 0 ) {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Search the VfrBin Base address.
+
+ According the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+ @param NumOfMachingOffset the number of Addr (Offset)
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+SearchVfrBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMachingOffset
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN VirOffValue;
+
+ Index = 0;
+ Status = EFI_SUCCESS;
+ VirOffValue = 0;
+
+ if ((Fv == NULL) || (Offset == NULL)) {
+ return EFI_ABORTED;
+ }
+ Status = GetAddressByGuid (
+ Fv,
+ &gVfrArrayAttractGuid,
+ Length,
+ Offset,
+ NumOfMachingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_ABORTED;
+ }
+
+ while (Index < *NumOfMachingOffset) {
+ //
+ // Got the virOffset after the GUID
+ //
+ VirOffValue = *(UINTN *)((UINTN)Fv + *(*Offset + Index));
+ //
+ //Transfer the offset to the VA address. One modules may own more VfrBin address.
+ //
+ *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
+ Index++;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Search the UniBin Base address.
+
+ According the known GUID gUniStrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+
+ @retval Base address Get the address successfully.
+**/
+EFI_STATUS
+SearchUniBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset
+ )
+{
+ UINT8 NumOfMachingOffset;
+ EFI_STATUS Status;
+ UINTN VirOffValue;
+
+ NumOfMachingOffset = 0;
+ Status = EFI_SUCCESS;
+ VirOffValue = 0;
+
+ if ((Fv == NULL) || (Offset == NULL)) {
+ return EFI_ABORTED;
+ }
+ Status = GetAddressByGuid (
+ Fv,
+ &gUniStrArrayAttractGuid,
+ Length,
+ Offset,
+ &NumOfMachingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_ABORTED;
+ }
+ //
+ //Transfer the offset to the VA address. There is only one UniArray in one modules.
+ //
+ if (NumOfMachingOffset == 1) {
+ VirOffValue = *(UINTN *)((UINTN)Fv + **Offset);
+ **Offset = (UINTN) EfiAddr + VirOffValue;
+ } else {
+ printf ("Error. Find more than 1 UniBin in FFS.\n");
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SearchNvStoreDatabaseInFd(
+ IN VOID *Fv,
+ IN UINTN length
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
+ Status = EFI_SUCCESS;
+ Offset = 0;
+ if (Fv == NULL) {
+ printf ("The FV is NULL.");
+ return EFI_ABORTED;
+ }
+ while (Offset < (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER))){
+ NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)((UINT8*)Fv + Offset);
+ if (NvStoreHeader->Signature == PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE) {
+ gEfiFdInfo.ExistNvStoreDatabase = TRUE;
+ gEfiFdInfo.NvStoreDatabase = (UINT8 *) NvStoreHeader;
+ break;
+ }
+ Offset++;
+ }
+ if (Offset == (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) || gEfiFdInfo.ExistNvStoreDatabase != TRUE) {
+ //printf ("Not found the PcdNvStoreDefaultValueBuffer\n");
+ return Status;
+ }
+ return Status;
+}
+
+/**
+ Get the address by Guid.
+
+ Parse the FD image, and find the GUID address.There may be some Guids matching the
+ searched Guid.
+
+ @param Fv the Pointer to the image.
+ @param Guid The Guid need to find.
+ @param Offset The dual Pointer to the offset.
+ @param NumOfMatchGuid The number of matching Guid offset.
+
+ @retval EFI_SUCCESS The Search was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+GetVariableAddressByGuid (
+ IN VOID *Fv,
+ IN EFI_GUID *Guid,
+ IN UINTN Len,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchGuid
+ )
+{
+ UINTN NextOffset;
+ UINT8 Flag;
+
+ if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) ){
+ return EFI_ABORTED;
+ }
+
+ Flag = 0;
+ NextOffset = 0;
+
+ if (NumOfMatchGuid != NULL) {
+ *NumOfMatchGuid = 0;
+ }
+ while (GetNextOffset(Fv, Guid, Len, &NextOffset)) {
+ Flag = 1;
+ if (NumOfMatchGuid != NULL && Offset != NULL) {
+ if (*NumOfMatchGuid == 0) {
+ *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ if (*Offset == NULL) {
+ return EFI_ABORTED;
+ }
+ memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ }
+ *(*Offset + *NumOfMatchGuid) = NextOffset;
+ (*NumOfMatchGuid)++;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if( Flag == 0 ) {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Search the EFI Variable Base address.
+
+ According the known GUID gEfiSystemNvDataFvGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+ @param NumOfMachingOffset the number of IFR array in one FFS
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_ABORTED An error occured.
+**/
+EFI_STATUS
+SearchEfiVarInFFS (
+ IN VOID *Fv,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMachingOffset
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+
+ if ((Fv == NULL) || (Offset == NULL)) {
+ printf ("The FV or offset is NULL.");
+ return EFI_ABORTED;
+ }
+ Status = GetVariableAddressByGuid (
+ Fv,
+ &gEfiSystemNvDataFvGuid,
+ Length,
+ Offset,
+ NumOfMachingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_ABORTED;
+ }
+ //
+ //Transfer the offset to the VA address.
+ //
+ while (Index < *NumOfMachingOffset) {
+ *(*Offset + Index) = (UINTN) Fv + *(*Offset + Index);
+ Index++;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse the Ffs header to get the size.
+
+ @param InputFile The pointer to the input file
+ @param FvSize The pointer to the file size
+
+ @return EFI_SUCCESS Get the file size successfully
+**/
+EFI_STATUS
+ReadFfsHeader (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+ EFI_FFS_FILE_HEADER FfsHeader;
+ EFI_FV_FILETYPE Type;
+
+ //
+ // Check input parameters
+ //
+ if ((InputFile == NULL) || (FvSize == NULL)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Read the header
+ //
+ fread (
+ &FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER),
+ 1,
+ InputFile
+ );
+ Type = FfsHeader.Type;
+
+ if (Type == EFI_FV_FILETYPE_DRIVER) {
+ *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+ } else if (Type == EFI_FV_FILETYPE_APPLICATION) {
+ *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+ } else if (Type == EFI_FV_FILETYPE_FREEFORM) {
+ *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+ } else {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/*
+ Read the length of the whole FD
+
+ This function determines the size of the FV.
+
+ @param InputFile The file that contains the FV image.
+ @param FvSize The size of the FV.
+
+ @retval EFI_SUCCESS The application exited normally.
+ @retval EFI_ABORTED An error occurred.
+
+**/
+static
+EFI_STATUS
+ReadFdHeader (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+ //
+ // Check input parameters
+ //
+ if ((InputFile == NULL) || (FvSize == NULL)) {
+ return EFI_ABORTED;
+ }
+ *FvSize = 0;
+ //
+ // Get the total size of FD file (Fixed the length)
+ //
+ fseek(InputFile,0,SEEK_END);
+ *FvSize = ftell(InputFile);
+ fseek(InputFile,0,SEEK_SET);
+
+ if (*FvSize == 0) {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the file to memory.
+
+ @param InputFile The file that contains the FV image.
+ @param Size The size of the file.
+
+ @retval The pointer to the begining position of memory.
+**/
+VOID *
+ReadFileToMemory (
+ IN CHAR8 *FileName,
+ OUT UINT32 *Size
+ )
+{
+ FILE *InFile;
+ VOID *Address;
+ UINT32 BytesRead;
+ EFI_STATUS Status;
+
+ InFile = NULL;
+ Address = NULL;
+ BytesRead = 0;
+ Status = EFI_SUCCESS;
+
+ InFile = fopen (FileName,"rb");
+ if (InFile == NULL) {
+ return NULL;
+ }
+ //
+ // Determine the size of FV
+ //
+ Status = ReadFdHeader (InFile, Size);
+ if (Status != EFI_SUCCESS) {
+ fclose (InFile);
+ return NULL;
+ }
+ //
+ // Allocate a buffer for the FV image
+ //
+ Address = malloc (*Size);
+ if (Address == NULL) {
+ fclose (InFile);
+ return NULL;
+ }
+ memset (Address, 0, *Size);
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (InFile, 0, SEEK_SET);
+ BytesRead = fread (Address, 1, *Size, InFile);
+ fclose (InFile);
+ if ((UINTN) BytesRead != *Size) {
+ free (Address);
+ return NULL;
+ }
+ return Address;
+}
+
+/**
+ Search the EFI variables address in Fd.
+
+ Open and read the *.fd to the memory, initialize the global structure.
+ Update the EFI variables addr and the begining position of memory.
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+GetEfiVariablesAddr (
+ BOOLEAN UqiIsSet
+ )
+{
+ VOID *FdImage;
+ UINT32 FdSize;
+ EFI_STATUS Status;
+ UINTN *EfiVarAddr;
+ UINT8 NumOfMachingVar;
+ UINT32 Index;
+ BOOLEAN GotFlag;
+ EFI_FIRMWARE_VOLUME_HEADER *Variable;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+ BOOLEAN NormalOrNot;
+
+ FdImage = NULL;
+ FdSize = 0;
+ Status = EFI_SUCCESS;
+ EfiVarAddr = NULL;
+ NumOfMachingVar = 0;
+ Index = 0;
+ GotFlag = TRUE;
+ Variable = NULL;
+
+ FdImage = ReadFileToMemory (mInputFdName, &FdSize);
+ if (FdImage == NULL) {
+ return EFI_ABORTED;
+ }
+ if (!UqiIsSet) {
+ Status = SearchNvStoreDatabaseInFd(FdImage, FdSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ Status = SearchEfiVarInFFS (
+ FdImage,
+ FdSize,
+ &EfiVarAddr,
+ &NumOfMachingVar
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Check the signature "_FVH"
+ //
+ Index = 0;
+ GotFlag = FALSE;
+
+ while (Index < NumOfMachingVar) {
+ Variable = (EFI_FIRMWARE_VOLUME_HEADER *)(*(EfiVarAddr + Index) - 0x20);
+ if (Variable->Signature == 0x4856465F) {
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore ((UINT8 *)Variable + Variable->HeaderLength);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
+ NormalOrNot = CheckNormalVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
+ if (AuthencitatedMonotonicOrNot || AuthencitatedBasedTimeOrNot || NormalOrNot) {
+ GotFlag = TRUE;
+ gEfiFdInfo.EfiVariableAddr = (UINTN)Variable;
+ break;
+ }
+ }
+ Index++;
+ }
+ free (EfiVarAddr);
+ if (!GotFlag) {
+ return EFI_ABORTED;
+ }
+ gEfiFdInfo.Fd = FdImage;
+ gEfiFdInfo.FdSize = FdSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pick up the FFS which includes IFR section.
+
+ Parse all FFS extracted by BfmLib, and save all which includes IFR
+ Binary to gEfiFdInfo structure.
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated.
+ @retval EFI_ABORTED Read FFS Failed.
+**/
+EFI_STATUS
+FindFileInFolder (
+ IN CHAR8 *FolderName,
+ OUT BOOLEAN *ExistStorageInBfv,
+ OUT BOOLEAN *SizeOptimized
+)
+{
+ CHAR8 *FileName;
+ CHAR8 *CurFolderName;
+ EFI_STATUS Status;
+ UINTN MaxFileNameLen;
+ UINTN Index;
+ CHAR8 FileNameArry[MAX_FILENAME_LEN];
+ FILE *FfsFile;
+ UINTN FileSize;
+ VOID *FfsImage;
+ UINTN BytesRead;
+#ifndef __GNUC__
+ HANDLE FindHandle;
+ WIN32_FIND_DATA FindFileData;
+#else
+ struct dirent *pDirent;
+ DIR *pDir;
+#endif
+
+ FileName = NULL;
+ CurFolderName = NULL;
+ Status = EFI_SUCCESS;
+ MaxFileNameLen = 0;
+ Index = 0;
+ FileSize = 0;
+ BytesRead = 0;
+ FfsImage = NULL;
+ FfsFile = NULL;
+
+ MaxFileNameLen = strlen (FolderName) + MAX_FILENAME_LEN;
+ CurFolderName = (CHAR8 *)calloc(
+ strlen (FolderName) + strlen (OS_SEP_STR) + strlen ("*.*")+ 1,
+ sizeof(CHAR8)
+ );
+ if (CurFolderName == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ strcpy (CurFolderName, FolderName);
+ strcat (CurFolderName, OS_SEP_STR);
+ strcat (CurFolderName, "*.*");
+ FileName = (CHAR8 *)calloc(
+ MaxFileNameLen,
+ sizeof(CHAR8)
+ );
+ if (FileName == NULL) {
+ free (CurFolderName);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+#ifndef __GNUC__
+ if((FindHandle = FindFirstFile(CurFolderName, &FindFileData)) != INVALID_HANDLE_VALUE){
+ do {
+ memset (FileName, 0, MaxFileNameLen);
+ if ((strcmp (FindFileData.cFileName, ".") == 0)
+ || (strcmp (FindFileData.cFileName, "..") == 0)
+ ) {
+ continue;
+ }
+ if (strlen(FolderName) + strlen ("\\") + strlen (FindFileData.cFileName) > MAX_FILENAME_LEN - 1) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ snprintf (FileNameArry, MAX_FILENAME_LEN, "%s%c%s", FolderName, OS_SEP, FindFileData.cFileName);
+ FfsFile = fopen (FileNameArry, "rb");
+ if (FfsFile == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
+ if (EFI_ERROR (Status)) {
+ fclose (FfsFile);
+ Status = EFI_SUCCESS;
+ continue;
+ }
+ //
+ // Allocate a buffer for the FFS file
+ //
+ FfsImage = malloc (FileSize);
+ if (FfsImage == NULL) {
+ fclose (FfsFile);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (FfsFile, 0, SEEK_SET);
+ BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
+ fclose (FfsFile);
+
+ if ((UINTN) BytesRead != FileSize) {
+ free (FfsImage);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Check whether exists the storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = FALSE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether exists the optimized storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = TRUE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether current FFS includes IFR
+ //
+ Status = GetAddressByGuid (
+ FfsImage,
+ &gVfrArrayAttractGuid,
+ FileSize,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ free (FfsImage);
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Check whether existed same IFR binary. If existed, not insert the new one.
+ //
+ if (NotExistSameFfsIfr (FfsImage)) {
+ gEfiFdInfo.FfsArray[Index] = FfsImage;
+ gEfiFdInfo.Length[Index++] = FileSize;
+ }
+ }
+
+ } while (FindNextFile (FindHandle, &FindFileData));
+ FindClose(FindHandle);
+ } else {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+Done:
+ free (CurFolderName);
+ free (FileName);
+
+#else
+ if((pDir = opendir(FolderName)) != NULL){
+ while ((pDirent = readdir(pDir)) != NULL){
+ memset (FileName, 0, MaxFileNameLen);
+ if ((strcmp (pDirent->d_name, ".") == 0)
+ || (strcmp (pDirent->d_name, "..") == 0)
+ ) {
+ continue;
+ }
+ sprintf (FileNameArry, "%s%c%s", FolderName, OS_SEP, pDirent->d_name);
+ FfsFile = fopen (FileNameArry, "rb");
+ Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
+ if (EFI_ERROR (Status)) {
+ fclose (FfsFile);
+ Status = EFI_SUCCESS;
+ continue;
+ }
+ //
+ // Allocate a buffer for the FFS file
+ //
+ FfsImage = malloc (FileSize);
+ if (FfsImage == NULL) {
+ fclose (FfsFile);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (FfsFile, 0, SEEK_SET);
+ BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
+ fclose (FfsFile);
+
+ if ((UINTN) BytesRead != FileSize) {
+ free (FfsImage);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Check whether exists the storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = FALSE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether exists the optimized storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = TRUE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether current FFS includes IFR
+ //
+ Status = GetAddressByGuid (
+ FfsImage,
+ &gVfrArrayAttractGuid,
+ FileSize,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ free (FfsImage);
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Check whether existed same IFR binary. If existed, not insert the new one.
+ //
+ if (NotExistSameFfsIfr (FfsImage)) {
+ gEfiFdInfo.FfsArray[Index] = FfsImage;
+ gEfiFdInfo.Length[Index++] = FileSize;
+ }
+ }
+
+ }
+ closedir(pDir);
+ } else {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+Done:
+ free (CurFolderName);
+ free (FileName);
+#endif
+ return Status;
+}
+
diff --git a/BaseTools/Source/C/FCE/Common.c b/BaseTools/Source/C/FCE/Common.c
new file mode 100644
index 0000000000..9b14a24a9b
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Common.c
@@ -0,0 +1,2183 @@
+/** @file
+
+ Common library.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "Common.h"
+
+#define WARNING_STATUS_NUMBER 4
+#define ERROR_STATUS_NUMBER 24
+
+CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+CONST CHAR8 *mStatusString[] = {
+ "Success", // RETURN_SUCCESS = 0
+ "Warning Unknown Glyph", // RETURN_WARN_UNKNOWN_GLYPH = 1
+ "Warning Delete Failure", // RETURN_WARN_DELETE_FAILURE = 2
+ "Warning Write Failure", // RETURN_WARN_WRITE_FAILURE = 3
+ "Warning Buffer Too Small", // RETURN_WARN_BUFFER_TOO_SMALL = 4
+ "Load Error", // RETURN_LOAD_ERROR = 1 | MAX_BIT
+ "Invalid Parameter", // RETURN_INVALID_PARAMETER = 2 | MAX_BIT
+ "Unsupported", // RETURN_UNSUPPORTED = 3 | MAX_BIT
+ "Bad Buffer Size", // RETURN_BAD_BUFFER_SIZE = 4 | MAX_BIT
+ "Buffer Too Small", // RETURN_BUFFER_TOO_SMALL, = 5 | MAX_BIT
+ "Not Ready", // RETURN_NOT_READY = 6 | MAX_BIT
+ "Device Error", // RETURN_DEVICE_ERROR = 7 | MAX_BIT
+ "Write Protected", // RETURN_WRITE_PROTECTED = 8 | MAX_BIT
+ "Out of Resources", // RETURN_OUT_OF_RESOURCES = 9 | MAX_BIT
+ "Volume Corrupt", // RETURN_VOLUME_CORRUPTED = 10 | MAX_BIT
+ "Volume Full", // RETURN_VOLUME_FULL = 11 | MAX_BIT
+ "No Media", // RETURN_NO_MEDIA = 12 | MAX_BIT
+ "Media changed", // RETURN_MEDIA_CHANGED = 13 | MAX_BIT
+ "Not Found", // RETURN_NOT_FOUND = 14 | MAX_BIT
+ "Access Denied", // RETURN_ACCESS_DENIED = 15 | MAX_BIT
+ "No Response", // RETURN_NO_RESPONSE = 16 | MAX_BIT
+ "No mapping", // RETURN_NO_MAPPING = 17 | MAX_BIT
+ "Time out", // RETURN_TIMEOUT = 18 | MAX_BIT
+ "Not started", // RETURN_NOT_STARTED = 19 | MAX_BIT
+ "Already started", // RETURN_ALREADY_STARTED = 20 | MAX_BIT
+ "Aborted", // RETURN_ABORTED = 21 | MAX_BIT
+ "ICMP Error", // RETURN_ICMP_ERROR = 22 | MAX_BIT
+ "TFTP Error", // RETURN_TFTP_ERROR = 23 | MAX_BIT
+ "Protocol Error" // RETURN_PROTOCOL_ERROR = 24 | MAX_BIT
+};
+
+/**
+ Copies one Null-terminated Unicode string to another Null-terminated Unicode
+ string and returns the new Unicode string.
+
+ This function copies the contents of the Unicode string Source to the Unicode
+ string Destination, and returns Destination. If Source and Destination
+ overlap, then the results are undefined.
+
+ If Destination is NULL, then return NULL.
+ If Destination is not aligned on a 16-bit boundary, then return NULL.
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCpy (
+ OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ )
+{
+ CHAR16 *ReturnValue;
+
+ ReturnValue = NULL;
+
+ if ((Destination == NULL) || ((UINTN) Destination % 2 != 0)) {
+ return NULL;
+ }
+
+ ReturnValue = Destination;
+ while (*Source != 0) {
+ *(Destination++) = *(Source++);
+ }
+ *Destination = 0;
+ return ReturnValue;
+}
+
+/**
+ Returns the length of a Null-terminated Unicode string.
+
+ This function returns the number of Unicode characters in the Null-terminated
+ Unicode string specified by String.
+
+ If String is NULL, then return 0.
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The length of String.
+
+**/
+UINTN
+FceStrLen (
+ IN CONST CHAR16 *String
+ )
+{
+ UINTN Length;
+
+ if (String == NULL) {
+ return 0;
+ }
+ for (Length = 0; *String != L'\0'; String++, Length++) {
+ ;
+ }
+ return Length;
+}
+
+/**
+ Returns the size of a Null-terminated Unicode string in bytes, including the
+ Null terminator.
+
+ This function returns the size, in bytes, of the Null-terminated Unicode string
+ specified by String.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The size of String.
+
+**/
+UINTN
+FceStrSize (
+ IN CONST CHAR16 *String
+ )
+{
+ return (FceStrLen (String) + 1) * sizeof (*String);
+}
+
+/**
+ Compares two Null-terminated Unicode strings, and returns the difference
+ between the first mismatched Unicode characters.
+
+ This function compares the Null-terminated Unicode string FirstString to the
+ Null-terminated Unicode string SecondString. If FirstString is identical to
+ SecondString, then 0 is returned. Otherwise, the value returned is the first
+ mismatched Unicode character in SecondString subtracted from the first
+ mismatched Unicode character in FirstString.
+
+ @param FirstString A pointer to a Null-terminated Unicode string.
+ @param SecondString A pointer to a Null-terminated Unicode string.
+
+ @retval 0 FirstString is identical to SecondString.
+ @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+FceStrCmp (
+ IN CONST CHAR16 *FirstString,
+ IN CONST CHAR16 *SecondString
+ )
+{
+ while ((*FirstString != L'\0') && (*FirstString == *SecondString)) {
+ FirstString++;
+ SecondString++;
+ }
+ return *FirstString - *SecondString;
+}
+
+/**
+ Concatenates one Null-terminated Unicode string to another Null-terminated
+ Unicode string, and returns the concatenated Unicode string.
+
+ This function concatenates two Null-terminated Unicode strings. The contents
+ of Null-terminated Unicode string Source are concatenated to the end of
+ Null-terminated Unicode string Destination. The Null-terminated concatenated
+ Unicode String is returned. If Source and Destination overlap, then the
+ results are undefined.
+
+ If Destination is NULL, then ASSERT().
+ If Destination is not aligned on a 16-bit boundary, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+ than PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+ and Source results in a Unicode string with more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCat (
+ IN OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ )
+{
+ StrCpy (Destination + FceStrLen (Destination), Source);
+
+ //
+ // Size of the resulting string should never be zero.
+ // PcdMaximumUnicodeStringLength is tested inside FceStrLen().
+ //
+ ASSERT (FceStrSize (Destination) != 0);
+ return Destination;
+}
+
+/**
+ Returns the first occurrence of a Null-terminated Unicode sub-string
+ in a Null-terminated Unicode string.
+
+ This function scans the contents of the Null-terminated Unicode string
+ specified by String and returns the first occurrence of SearchString.
+ If SearchString is not found in String, then NULL is returned. If
+ the length of SearchString is zero, then String is
+ returned.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If SearchString is NULL, then ASSERT().
+ If SearchString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and SearchString
+ or String contains more than PcdMaximumUnicodeStringLength Unicode
+ characters, not including the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+ @param SearchString A pointer to a Null-terminated Unicode string to search for.
+
+ @retval NULL If the SearchString does not appear in String.
+ @return others If there is a match.
+
+**/
+CHAR16 *
+StrStr (
+ IN CONST CHAR16 *String,
+ IN CONST CHAR16 *SearchString
+ )
+{
+ CONST CHAR16 *FirstMatch;
+ CONST CHAR16 *SearchStringTmp;
+
+ //
+ // ASSERT both strings are less long than PcdMaximumUnicodeStringLength.
+ // Length tests are performed inside FceStrLen().
+ //
+ ASSERT (FceStrSize (String) != 0);
+ ASSERT (FceStrSize (SearchString) != 0);
+
+ if (*SearchString == L'\0') {
+ return (CHAR16 *) String;
+ }
+
+ while (*String != L'\0') {
+ SearchStringTmp = SearchString;
+ FirstMatch = String;
+
+ while ((*String == *SearchStringTmp)
+ && (*String != L'\0')) {
+ String++;
+ SearchStringTmp++;
+ }
+
+ if (*SearchStringTmp == L'\0') {
+ return (CHAR16 *) FirstMatch;
+ }
+
+ if (*String == L'\0') {
+ return NULL;
+ }
+
+ String = FirstMatch + 1;
+ }
+
+ return NULL;
+}
+
+/**
+ Convert one Null-terminated ASCII string to a Null-terminated
+ Unicode string and returns the Unicode string.
+
+ This function converts the contents of the ASCII string Source to the Unicode
+ string Destination, and returns Destination. The function terminates the
+ Unicode string Destination by appending a Null-terminator character at the end.
+ The caller is responsible to make sure Destination points to a buffer with size
+ equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
+
+ @param Source A pointer to a Null-terminated ASCII string.
+ @param Destination A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+ @return NULL If Destination or Source is NULL, return NULL.
+
+**/
+CHAR16 *
+AsciiStrToUnicodeStr (
+ IN CONST CHAR8 *Source,
+ OUT CHAR16 *Destination
+ )
+{
+ CHAR16 *ReturnValue;
+
+ ReturnValue = NULL;
+
+ if ((Destination == NULL) || (Source == NULL) || (strlen (Source) == 0)) {
+ return NULL;
+ }
+ ReturnValue = Destination;
+ while (*Source != '\0') {
+ *(Destination++) = (CHAR16) *(Source++);
+ }
+ //
+ // End the Destination with a NULL.
+ //
+ *Destination = '\0';
+
+ return ReturnValue;
+}
+
+/**
+ Internal function that convert a number to a string in Buffer.
+
+ Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
+
+ @param Buffer Location to place the ASCII string of Value.
+ @param Value The value to convert to a Decimal or Hexadecimal string in Buffer.
+ @param Radix Radix of the value
+
+ @return A pointer to the end of buffer filled with ASCII string.
+
+**/
+CHAR8 *
+BasePrintLibValueToString (
+ IN OUT CHAR8 *Buffer,
+ IN INT64 Value,
+ IN UINTN Radix
+ )
+{
+ UINT32 Remainder;
+
+ //
+ // Loop to convert one digit at a time in reverse order
+ //
+ *Buffer = 0;
+ do {
+ Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
+ *(++Buffer) = mHexStr[Remainder];
+ } while (Value != 0);
+
+ //
+ // Return pointer of the end of filled buffer.
+ //
+ return Buffer;
+}
+
+/**
+ Reads a 16-bit value from memory that may be unaligned.
+
+ This function returns the 16-bit value pointed to by Buffer. The function
+ guarantees that the read operation does not produce an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 16-bit value that may be unaligned.
+
+ @return The 16-bit value read from Buffer.
+
+**/
+UINT16
+FceReadUnaligned16 (
+ IN CONST UINT16 *Buffer
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer;
+}
+
+/**
+ Reads a 32-bit value from memory that may be unaligned.
+
+ This function returns the 32-bit value pointed to by Buffer. The function
+ guarantees that the read operation does not produce an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 32-bit value that may be unaligned.
+
+ @return The 32-bit value read from Buffer.
+
+**/
+UINT32
+ReadUnaligned32 (
+ IN CONST UINT32 *Buffer
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer;
+}
+
+/**
+ Internal function that places the character into the Buffer.
+
+ Internal function that places ASCII or Unicode character into the Buffer.
+
+ @param Buffer The buffer to place the Unicode or ASCII string.
+ @param EndBuffer The end of the input Buffer. No characters will be
+ placed after that.
+ @param Length The count of character to be placed into Buffer.
+ (Negative value indicates no buffer fill.)
+ @param Character The character to be placed into Buffer.
+ @param Increment The character increment in Buffer.
+
+ @return Buffer.
+
+**/
+CHAR8 *
+BasePrintLibFillBuffer (
+ OUT CHAR8 *Buffer,
+ IN CHAR8 *EndBuffer,
+ IN INTN Length,
+ IN UINTN Character,
+ IN INTN Increment
+ )
+{
+ INTN Index;
+
+ for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
+ *Buffer = (CHAR8) Character;
+ if (Increment != 1) {
+ *(Buffer + 1) = (CHAR8)(Character >> 8);
+ }
+ Buffer += Increment;
+ }
+
+ return Buffer;
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and a VA_LIST argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine.
+
+ If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
+
+ @param[out] Buffer The character buffer to print the results of the
+ parsing of Format into.
+ @param[in] BufferSize The maximum number of characters to put into
+ buffer.
+ @param[in] Flags Initial flags value.
+ Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
+ and COUNT_ONLY_NO_PRINT set.
+ @param[in] Format A Null-terminated format string.
+ @param[in] VaListMarker VA_LIST style variable argument list consumed by
+ processing Format.
+ @param[in] BaseListMarker BASE_LIST style variable argument list consumed
+ by processing Format.
+
+ @return The number of characters printed not including the Null-terminator.
+ If COUNT_ONLY_NO_PRINT was set returns the same, but without any
+ modification to Buffer.
+
+**/
+UINTN
+BasePrintLibSPrintMarker (
+ OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker, OPTIONAL
+ IN BASE_LIST BaseListMarker OPTIONAL
+ )
+{
+ CHAR8 *OriginalBuffer;
+ CHAR8 *EndBuffer;
+ CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
+ UINT32 BytesPerOutputCharacter;
+ UINTN BytesPerFormatCharacter;
+ UINTN FormatMask;
+ UINTN FormatCharacter;
+ UINTN Width;
+ UINTN Precision;
+ INT64 Value;
+ CONST CHAR8 *ArgumentString;
+ UINTN Character;
+ EFI_GUID *TmpGuid;
+ TIME *TmpTime;
+ UINTN Count;
+ UINTN ArgumentMask;
+ INTN BytesPerArgumentCharacter;
+ UINTN ArgumentCharacter;
+ BOOLEAN Done;
+ UINTN Index;
+ CHAR8 Prefix;
+ BOOLEAN ZeroPad;
+ BOOLEAN Comma;
+ UINTN Digits;
+ UINTN Radix;
+ RETURN_STATUS Status;
+ UINT32 GuidData1;
+ UINT16 GuidData2;
+ UINT16 GuidData3;
+ UINTN LengthToReturn;
+
+ //
+ // If you change this code be sure to match the 2 versions of this function.
+ // Nearly identical logic is found in the BasePrintLib and
+ // DxePrintLibPrint2Protocol (both PrintLib instances).
+ //
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ if (BufferSize == 0) {
+ Buffer = NULL;
+ }
+ } else {
+ //
+ // We can run without a Buffer for counting only.
+ //
+ if (BufferSize == 0) {
+ return 0;
+ }
+ ASSERT (Buffer != NULL);
+ }
+
+ if ((Flags & OUTPUT_UNICODE) != 0) {
+ BytesPerOutputCharacter = 2;
+ } else {
+ BytesPerOutputCharacter = 1;
+ }
+
+ LengthToReturn = 0;
+
+ //
+ // Reserve space for the Null terminator.
+ //
+ BufferSize--;
+ OriginalBuffer = Buffer;
+
+ //
+ // Set the tag for the end of the input Buffer.
+ //
+ EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;
+
+ if ((Flags & FORMAT_UNICODE) != 0) {
+ //
+ // Make sure format string cannot contain more than PcdMaximumUnicodeStringLength
+ // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+ //
+ ASSERT (FceStrSize ((CHAR16 *) Format) != 0);
+ BytesPerFormatCharacter = 2;
+ FormatMask = 0xffff;
+ } else {
+ //
+ // Make sure format string cannot contain more than PcdMaximumAsciiStringLength
+ // Ascii characters if PcdMaximumAsciiStringLength is not zero.
+ //
+ ASSERT (strlen (Format) + 1 != 0);
+ BytesPerFormatCharacter = 1;
+ FormatMask = 0xff;
+ }
+
+ //
+ // Get the first character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+
+ //
+ // Loop until the end of the format string is reached or the output buffer is full
+ //
+ while (FormatCharacter != 0 && Buffer < EndBuffer) {
+ //
+ // Clear all the flag bits except those that may have been passed in
+ //
+ Flags &= (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
+
+ //
+ // Set the default width to zero, and the default precision to 1
+ //
+ Width = 0;
+ Precision = 1;
+ Prefix = 0;
+ Comma = FALSE;
+ ZeroPad = FALSE;
+ Count = 0;
+ Digits = 0;
+
+ switch (FormatCharacter) {
+ case '%':
+ //
+ // Parse Flags and Width
+ //
+ for (Done = FALSE; !Done; ) {
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ switch (FormatCharacter) {
+ case '.':
+ Flags |= PRECISION;
+ break;
+ case '-':
+ Flags |= LEFT_JUSTIFY;
+ break;
+ case '+':
+ Flags |= PREFIX_SIGN;
+ break;
+ case ' ':
+ Flags |= PREFIX_BLANK;
+ break;
+ case ',':
+ Flags |= COMMA_TYPE;
+ break;
+ case 'L':
+ case 'l':
+ Flags |= LONG_TYPE;
+ break;
+ case '*':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ if (BaseListMarker == NULL) {
+ Width = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Width = BASE_ARG (BaseListMarker, UINTN);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Precision = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Precision = BASE_ARG (BaseListMarker, UINTN);
+ }
+ }
+ break;
+ case '0':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PREFIX_ZERO;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ for (Count = 0; ((FormatCharacter >= '0') && (FormatCharacter <= '9')); ){
+ Count = (Count * 10) + FormatCharacter - '0';
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ }
+ Format -= BytesPerFormatCharacter;
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ Width = Count;
+ } else {
+ Precision = Count;
+ }
+ break;
+
+ case '\0':
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format -= BytesPerFormatCharacter;
+ Precision = 0;
+ //
+ // break skipped on purpose.
+ //
+ default:
+ Done = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Handle each argument type
+ //
+ switch (FormatCharacter) {
+ case 'p':
+ //
+ // Flag space, +, 0, L & l are invalid for type p.
+ //
+ Flags &= ~(PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE);
+ if (sizeof (VOID *) > 4) {
+ Flags |= LONG_TYPE;
+ }
+ case 'X':
+ Flags |= PREFIX_ZERO;
+ //
+ // break skipped on purpose
+ //
+ case 'x':
+ Flags |= RADIX_HEX;
+ //
+ // break skipped on purpose
+ //
+ case 'd':
+ if ((Flags & LONG_TYPE) == 0) {
+ //
+ // 'd','x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "int" is used in this one case.
+ //
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, int);
+ } else {
+ Value = BASE_ARG (BaseListMarker, int);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, INT64);
+ } else {
+ Value = BASE_ARG (BaseListMarker, INT64);
+ }
+ }
+ if ((Flags & PREFIX_BLANK) != 0) {
+ Prefix = ' ';
+ }
+ if ((Flags & PREFIX_SIGN) != 0) {
+ Prefix = '+';
+ }
+ if ((Flags & COMMA_TYPE) != 0) {
+ Comma = TRUE;
+ }
+ if ((Flags & RADIX_HEX) == 0) {
+ Radix = 10;
+ if (Comma) {
+ Flags &= (~PREFIX_ZERO);
+ Precision = 1;
+ }
+ if (Value < 0) {
+ Flags |= PREFIX_SIGN;
+ Prefix = '-';
+ Value = -Value;
+ }
+ } else {
+ Radix = 16;
+ Comma = FALSE;
+ if ((Flags & LONG_TYPE) == 0 && Value < 0) {
+ //
+ // 'd','x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "unsigned int" is used in this one case.
+ //
+ Value = (unsigned int)Value;
+ }
+ }
+ //
+ // Convert Value to a reversed string
+ //
+ Count = BasePrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
+ if (Value == 0 && Precision == 0) {
+ Count = 0;
+ }
+ ArgumentString = (CHAR8 *)ValueBuffer + Count;
+
+ Digits = Count % 3;
+ if (Digits != 0) {
+ Digits = 3 - Digits;
+ }
+ if (Comma && Count != 0) {
+ Count += ((Count - 1) / 3);
+ }
+ if (Prefix != 0) {
+ Count++;
+ Precision++;
+ }
+ Flags |= ARGUMENT_REVERSED;
+ ZeroPad = TRUE;
+ if ((Flags & PREFIX_ZERO) != 0) {
+ if ((Flags & LEFT_JUSTIFY) == 0) {
+ if ((Flags & PAD_TO_WIDTH) != 0) {
+ if ((Flags & PRECISION) == 0) {
+ Precision = Width;
+ }
+ }
+ }
+ }
+ break;
+
+ case 's':
+ case 'S':
+ Flags |= ARGUMENT_UNICODE;
+ //
+ // break skipped on purpose
+ //
+ case 'a':
+ if (BaseListMarker == NULL) {
+ ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
+ } else {
+ ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
+ }
+ if (ArgumentString == NULL) {
+ Flags &= (~ARGUMENT_UNICODE);
+ ArgumentString = "<null string>";
+ }
+ //
+ // Set the default precision for string to be zero if not specified.
+ //
+ if ((Flags & PRECISION) == 0) {
+ Precision = 0;
+ }
+ break;
+
+ case 'c':
+ if (BaseListMarker == NULL) {
+ Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
+ } else {
+ Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
+ }
+ ArgumentString = (CHAR8 *)&Character;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+
+ case 'g':
+ if (BaseListMarker == NULL) {
+ TmpGuid = VA_ARG (VaListMarker, EFI_GUID *);
+ } else {
+ TmpGuid = BASE_ARG (BaseListMarker, EFI_GUID *);
+ }
+ if (TmpGuid == NULL) {
+ ArgumentString = "<null guid>";
+ } else {
+ GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
+ GuidData2 = FceReadUnaligned16 (&(TmpGuid->Data2));
+ GuidData3 = FceReadUnaligned16 (&(TmpGuid->Data3));
+ BasePrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ GuidData1,
+ GuidData2,
+ GuidData3,
+ TmpGuid->Data4[0],
+ TmpGuid->Data4[1],
+ TmpGuid->Data4[2],
+ TmpGuid->Data4[3],
+ TmpGuid->Data4[4],
+ TmpGuid->Data4[5],
+ TmpGuid->Data4[6],
+ TmpGuid->Data4[7]
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 't':
+ if (BaseListMarker == NULL) {
+ TmpTime = VA_ARG (VaListMarker, TIME *);
+ } else {
+ TmpTime = BASE_ARG (BaseListMarker, TIME *);
+ }
+ if (TmpTime == NULL) {
+ ArgumentString = "<null time>";
+ } else {
+ BasePrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%02d/%02d/%04d %02d:%02d",
+ TmpTime->Month,
+ TmpTime->Day,
+ TmpTime->Year,
+ TmpTime->Hour,
+ TmpTime->Minute
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 'r':
+ if (BaseListMarker == NULL) {
+ Status = VA_ARG (VaListMarker, RETURN_STATUS);
+ } else {
+ Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
+ }
+ ArgumentString = ValueBuffer;
+ if (RETURN_ERROR (Status)) {
+ //
+ // Clear error bit
+ //
+ Index = Status & ~MAX_BIT;
+ if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
+ }
+ } else {
+ Index = Status;
+ if (Index <= WARNING_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index];
+ }
+ }
+ if (ArgumentString == ValueBuffer) {
+ BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '%':
+ default:
+ //
+ // if the type is '%' or unknown, then print it to the screen
+ //
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ default:
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+
+ //
+ // Retrieve the ArgumentString attriubutes
+ //
+ if ((Flags & ARGUMENT_UNICODE) != 0) {
+ ArgumentMask = 0xffff;
+ BytesPerArgumentCharacter = 2;
+ } else {
+ ArgumentMask = 0xff;
+ BytesPerArgumentCharacter = 1;
+ }
+ if ((Flags & ARGUMENT_REVERSED) != 0) {
+ BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
+ } else {
+ //
+ // Compute the number of characters in ArgumentString and store it in Count
+ // ArgumentString is either null-terminated, or it contains Precision characters
+ //
+ for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {
+ ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
+ if (ArgumentCharacter == 0) {
+ break;
+ }
+ }
+ }
+
+ if (Precision < Count) {
+ Precision = Count;
+ }
+
+ //
+ // Pad before the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ if (ZeroPad) {
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
+ }
+ } else {
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
+ }
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ }
+
+ //
+ // Output the Prefix character if it is present
+ //
+ Index = 0;
+ if (Prefix != 0) {
+ Index++;
+ }
+
+ //
+ // Copy the string into the output buffer performing the required type conversions
+ //
+ while (Index < Count) {
+ ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;
+
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
+ }
+ ArgumentString += BytesPerArgumentCharacter;
+ Index++;
+ if (Comma) {
+ Digits++;
+ if (Digits == 3) {
+ Digits = 0;
+ Index++;
+ if (Index < Count) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Pad after the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ }
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ return (LengthToReturn / BytesPerOutputCharacter);
+ }
+
+ ASSERT (Buffer != NULL);
+ //
+ // Null terminate the Unicode or ASCII string
+ //
+ BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
+ //
+ // Make sure output buffer cannot contain more than PcdMaximumUnicodeStringLength
+ // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+ //
+ ASSERT ((((Flags & OUTPUT_UNICODE) == 0)) || (FceStrSize ((CHAR16 *) OriginalBuffer) != 0));
+ //
+ // Make sure output buffer cannot contain more than PcdMaximumAsciiStringLength
+ // ASCII characters if PcdMaximumAsciiStringLength is not zero.
+ //
+ ASSERT ((((Flags & OUTPUT_UNICODE) != 0)) || ((strlen (OriginalBuffer) + 1) != 0));
+
+ return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and variable argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine
+
+ @param StartOfBuffer The character buffer to print the results of the parsing
+ of Format into.
+ @param BufferSize The maximum number of characters to put into buffer.
+ Zero means no limit.
+ @param Flags Initial flags value.
+ Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+ @param FormatString A Null-terminated format string.
+ @param ... The variable argument list.
+
+ @return The number of characters printed.
+
+**/
+UINTN
+BasePrintLibSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+
+ VA_START (Marker, FormatString);
+ return BasePrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on
+ a Null-terminated Unicode format string and a VA_LIST argument list
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+UnicodeVSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ ASSERT_UNICODE_BUFFER (StartOfBuffer);
+ ASSERT_UNICODE_BUFFER (FormatString);
+ return BasePrintLibSPrintMarker ((CHAR8 *)StartOfBuffer, BufferSize >> 1, FORMAT_UNICODE | OUTPUT_UNICODE, (CHAR8 *)FormatString, Marker, NULL);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+UnicodeSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+
+ VA_START (Marker, FormatString);
+ return UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Convert a Null-terminated Unicode string to a Null-terminated
+ ASCII string and returns the ASCII string.
+
+ This function converts the content of the Unicode string Source
+ to the ASCII string Destination by copying the lower 8 bits of
+ each Unicode character. It returns Destination. The function terminates
+ the ASCII string Destination by appending a Null-terminator character
+ at the end. The caller is responsible to make sure Destination points
+ to a buffer with size equal or greater than (FceStrLen (Source) + 1) in bytes.
+
+ If Destination is NULL, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+
+ If any Unicode characters in Source contain non-zero value in
+ the upper 8 bits, then ASSERT().
+
+ @param Source Pointer to a Null-terminated Unicode string.
+ @param Destination Pointer to a Null-terminated ASCII string.
+
+ @reture Destination
+
+**/
+CHAR8 *
+UnicodeStrToAsciiStr (
+ IN CONST CHAR16 *Source,
+ OUT CHAR8 *Destination
+ )
+{
+ CHAR8 *ReturnValue;
+
+ ReturnValue = Destination;
+ assert (Destination != NULL);
+ assert (Source != NULL);
+ assert (((UINTN) Source & 0x01) == 0);
+
+ while (*Source != L'\0') {
+ //
+ // If any Unicode characters in Source contain
+ // non-zero value in the upper 8 bits, then ASSERT().
+ //
+ assert (*Source < 0x100);
+ *(ReturnValue++) = (CHAR8) *(Source++);
+ }
+
+ *ReturnValue = '\0';
+
+ return Destination;
+}
+
+/**
+ Allocate new memory and then copy the Unicode string Source to Destination.
+
+ @param Dest Location to copy string
+ @param Src String to copy
+
+**/
+VOID
+NewStringCpy (
+ IN OUT CHAR16 **Dest,
+ IN CHAR16 *Src
+ )
+{
+ if (*Dest != NULL) {
+ FreePool (*Dest);
+ }
+ *Dest = FceAllocateCopyPool (FceStrSize (Src), Src);
+ ASSERT (*Dest != NULL);
+}
+
+/**
+ Check if a Unicode character is a decimal character.
+
+ This internal function checks if a Unicode character is a
+ decimal character. The valid decimal character is from
+ L'0' to L'9'.
+
+ @param Char The character to check against.
+
+ @retval TRUE If the Char is a decmial character.
+ @retval FALSE If the Char is not a decmial character.
+
+**/
+BOOLEAN
+FceInternalIsDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN) ((Char >= L'0') && (Char <= L'9'));
+}
+
+/**
+ Convert a Unicode character to upper case only if
+ it maps to a valid small-case ASCII character.
+
+ This internal function only deal with Unicode character
+ which maps to a valid small-case ASCII character, i.e.
+ L'a' to L'z'. For other Unicode character, the input character
+ is returned directly.
+
+ @param Char The character to convert.
+
+ @retval LowerCharacter If the Char is with range L'a' to L'z'.
+ @retval Unchanged Otherwise.
+
+**/
+CHAR16
+FceInternalCharToUpper (
+ IN CHAR16 Char
+ )
+{
+ if ((Char >= L'a') && (Char <= L'z')) {
+ return (CHAR16) (Char - (L'a' - L'A'));
+ }
+
+ return Char;
+}
+
+/**
+ Convert a Unicode character to numerical value.
+
+ This internal function only deal with Unicode character
+ which maps to a valid hexadecimal ASII character, i.e.
+ L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
+ Unicode character, the value returned does not make sense.
+
+ @param Char The character to convert.
+
+ @return The numerical value converted.
+
+**/
+UINTN
+FceInternalHexCharToUintn (
+ IN CHAR16 Char
+ )
+{
+ if (FceInternalIsDecimalDigitCharacter (Char)) {
+ return Char - L'0';
+ }
+
+ return (UINTN) (10 + FceInternalCharToUpper (Char) - L'A');
+}
+
+/**
+ Check if a Unicode character is a hexadecimal character.
+
+ This internal function checks if a Unicode character is a
+ decimal character. The valid hexadecimal character is
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
+
+
+ @param Char The character to check against.
+
+ @retval TRUE If the Char is a hexadecmial character.
+ @retval FALSE If the Char is not a hexadecmial character.
+
+**/
+BOOLEAN
+FceInternalIsHexaDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+
+ return (BOOLEAN) (FceInternalIsDecimalDigitCharacter (Char) ||
+ ((Char >= L'A') && (Char <= L'F')) ||
+ ((Char >= L'a') && (Char <= L'f')));
+}
+
+
+/**
+ Convert a Null-terminated Unicode decimal string to a value of
+ type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a decimal number. The format
+ of the input Unicode string String is:
+
+ [spaces] [decimal digits].
+
+ The valid decimal digit character is in the range [0-9]. The
+ function will ignore the pad space, which includes spaces or
+ tab characters, before [decimal digits]. The running zero in the
+ beginning of [decimal digits] will be ignored. Then, the function
+ stops at the first character that is a not a valid decimal character
+ or a Null-terminator, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then 0 is returned.
+ If String has no pad spaces or valid decimal digits,
+ then 0 is returned.
+ If the number represented by String overflows according
+ to the range defined by UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains
+ more than PcdMaximumUnicodeStringLength Unicode characters, not including
+ the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrDecimalToUint64 (
+ IN CONST CHAR16 *String
+ )
+{
+ UINT64 Result;
+
+ //
+ // ASSERT String is less long than PcdMaximumUnicodeStringLength.
+ // Length tests are performed inside FceStrLen().
+ //
+ ASSERT (FceStrSize (String) != 0);
+
+ //
+ // Ignore the pad spaces (space or tab)
+ //
+ while ((*String == L' ') || (*String == L'\t')) {
+ String++;
+ }
+
+ //
+ // Ignore leading Zeros after the spaces
+ //
+ while (*String == L'0') {
+ String++;
+ }
+
+ Result = 0;
+
+ while (FceInternalIsDecimalDigitCharacter (*String)) {
+ //
+ // If the number represented by String overflows according
+ // to the range defined by UINTN, then ASSERT().
+ //
+ ASSERT (Result <= DivU64x32 (((UINT64) ~0) - (*String - L'0') , 10));
+
+ Result = MultU64x32 (Result, 10) + (*String - L'0');
+ String++;
+ }
+
+ return Result;
+}
+
+
+/**
+ Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a hexadecimal number.
+ The format of the input Unicode string String is
+
+ [spaces][zeros][x][hexadecimal digits].
+
+ The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+ The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+ If "x" appears in the input string, it must be prefixed with at least one 0.
+ The function will ignore the pad space, which includes spaces or tab characters,
+ before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+ [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+ first valid hexadecimal digit. Then, the function stops at the first character that is
+ a not a valid hexadecimal character or NULL, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then zero is returned.
+ If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+ then zero is returned.
+ If the number represented by String overflows according to the range defined by
+ UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+ then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrHexToUint64 (
+ IN CONST CHAR16 *String
+ )
+{
+ UINT64 Result;
+
+ //
+ // ASSERT String is less long than PcdMaximumUnicodeStringLength.
+ // Length tests are performed inside FceStrLen().
+ //
+ ASSERT (FceStrSize (String) != 0);
+
+ //
+ // Ignore the pad spaces (space or tab)
+ //
+ while ((*String == L' ') || (*String == L'\t')) {
+ String++;
+ }
+
+ //
+ // Ignore leading Zeros after the spaces
+ //
+ while (*String == L'0') {
+ String++;
+ }
+
+ if (FceInternalCharToUpper (*String) == L'X') {
+ ASSERT (*(String - 1) == L'0');
+ if (*(String - 1) != L'0') {
+ return 0;
+ }
+ //
+ // Skip the 'X'
+ //
+ String++;
+ }
+
+ Result = 0;
+
+ while (FceInternalIsHexaDecimalDigitCharacter (*String)) {
+ //
+ // If the Hex Number represented by String overflows according
+ // to the range defined by UINTN, then ASSERT().
+ //
+ ASSERT (Result <= RShiftU64 (((UINT64) ~0) - FceInternalHexCharToUintn (*String) , 4));
+
+ Result = LShiftU64 (Result, 4);
+ Result = Result + FceInternalHexCharToUintn (*String);
+ String++;
+ }
+
+ return Result;
+}
+
+
+CHAR16
+ToUpper (
+ CHAR16 a
+ )
+{
+ if (('a' <= a) && (a <= 'z')) {
+ return (CHAR16) (a - 0x20);
+ } else {
+ return a;
+ }
+}
+
+CHAR16
+ToLower (
+ CHAR16 a
+ )
+{
+ if (('A' <= a) && (a <= 'Z')) {
+ return (CHAR16) (a + 0x20);
+ } else {
+ return a;
+ }
+}
+
+/**
+ Performs a case-insensitive comparison between a Null-terminated
+ Unicode pattern string and a Null-terminated Unicode string.
+
+ @param String - A pointer to a Null-terminated Unicode string.
+ @param Pattern - A pointer to a Null-terminated Unicode pattern string.
+
+
+ @retval TRUE - Pattern was found in String.
+ @retval FALSE - Pattern was not found in String.
+
+**/
+BOOLEAN
+MetaiMatch (
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ )
+{
+ CHAR16 c;
+ CHAR16 p;
+
+ assert (String != NULL);
+ assert (Pattern != NULL);
+
+ for (;;) {
+ p = *Pattern;
+ Pattern += 1;
+
+ if (p == 0) {
+ //
+ // End of pattern. If end of string, TRUE match
+ //
+ if (*String) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+ } else {
+
+ c = *String;
+ if (ToUpper (c) != ToUpper (p)) {
+ return FALSE;
+ }
+
+ String += 1;
+
+ }
+
+ }
+
+}
+/**
+ Multiplies a 64-bit unsigned integer by a 32-bit unsigned integer and
+ generates a 64-bit unsigned result.
+
+ This function multiplies the 64-bit unsigned value Multiplicand by the 32-bit
+ unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+ bit unsigned result is returned.
+
+ @param Multiplicand A 64-bit unsigned value.
+ @param Multiplier A 32-bit unsigned value.
+
+ @return Multiplicand * Multiplier.
+
+**/
+UINT64
+MultU64x32 (
+ IN UINT64 Multiplicand,
+ IN UINT32 Multiplier
+ )
+{
+ return Multiplicand * Multiplier;
+}
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. This
+ function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32 (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor
+ )
+{
+ ASSERT (Divisor != 0);
+ return Dividend / Divisor;
+}
+
+/**
+ Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
+ with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the left by Count bits. The
+ low Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift left.
+ @param Count The number of bits to shift left.
+
+ @return Operand << Count.
+
+**/
+UINT64
+LShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ )
+{
+ ASSERT (Count < 64);
+ return Operand << Count;
+}
+
+/**
+ Shifts a 64-bit integer right between 0 and 63 bits. This high bits are
+ filled with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the right by Count bits. The
+ high Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift right.
+ @param Count The number of bits to shift right.
+
+ @return Operand >> Count.
+
+**/
+UINT64
+RShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ )
+
+{
+ ASSERT (Count < 64);
+ return Operand >> Count;
+}
+
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result and an optional 32-bit unsigned remainder.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+ is not NULL, then the 32-bit unsigned remainder is returned in Remainder.
+ This function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+ @param Remainder A pointer to a 32-bit unsigned value. This parameter is
+ optional and may be NULL.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32Remainder (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor,
+ OUT UINT32 *Remainder
+ )
+{
+ ASSERT (Divisor != 0);
+
+ if (Remainder != NULL) {
+ *Remainder = (UINT32)(Dividend % Divisor);
+ }
+ return Dividend / Divisor;
+}
+
+/**
+ Copies a buffer to an allocated buffer.
+
+ Allocates the number bytes specified by AllocationSize, copies allocationSize bytes
+ from Buffer to the newly allocated buffer, 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.
+
+ If Buffer is NULL, then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+FceAllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ Memory = NULL;
+
+ if ((Buffer == NULL) || (AllocationSize == 0)) {
+ return Memory;
+ }
+
+ Memory = calloc (AllocationSize, sizeof (CHAR8));
+ if (Memory != NULL) {
+ Memory = memcpy (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Initializes the head node of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Initializes the forward and backward links of a new linked list. After
+ initializing a linked list with this function, the other linked list
+ functions may be used to add and remove nodes from the linked list. It is up
+ to the caller of this function to allocate the memory for ListHead.
+
+ If ListHead is NULL, then ASSERT().
+
+ @param ListHead A pointer to the head node of a new doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InitializeListHead (
+ IN OUT LIST_ENTRY *ListHead
+ )
+
+{
+ assert (ListHead != NULL);
+
+ ListHead->ForwardLink = ListHead;
+ ListHead->BackLink = ListHead;
+ return ListHead;
+}
+
+/**
+ Adds a node to the beginning of a doubly-linked list, and returns the pointer
+ to the head node of the doubly-linked list.
+
+ Adds the node Entry at the beginning of the doubly-linked list denoted by
+ ListHead, and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be inserted at the beginning
+ of a doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertHeadList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ )
+{
+ assert ((ListHead != NULL) && (Entry != NULL));
+
+ Entry->ForwardLink = ListHead->ForwardLink;
+ Entry->BackLink = ListHead;
+ Entry->ForwardLink->BackLink = Entry;
+ ListHead->ForwardLink = Entry;
+ return ListHead;
+}
+
+/**
+ Adds a node to the end of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Adds the node Entry to the end of the doubly-linked list denoted by ListHead,
+ and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be added at the end of the
+ doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertTailList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ )
+{
+ assert ((ListHead != NULL) && (Entry != NULL));
+
+ Entry->ForwardLink = ListHead;
+ Entry->BackLink = ListHead->BackLink;
+ Entry->BackLink->ForwardLink = Entry;
+ ListHead->BackLink = Entry;
+ return ListHead;
+}
+
+/**
+ Retrieves the first node of a doubly-linked list.
+
+ Returns the first node of a doubly-linked list. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+ If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+
+ @return The first node of a doubly-linked list.
+ @retval NULL The list is empty.
+
+**/
+LIST_ENTRY *
+GetFirstNode (
+ IN CONST LIST_ENTRY *List
+ )
+{
+ assert (List != NULL);
+
+ return List->ForwardLink;
+}
+
+/**
+ Retrieves the next node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that follows Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the next node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetNextNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return Node->ForwardLink;
+}
+
+/**
+ Retrieves the previous node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that precedes Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the previous node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetPreviousNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return Node->BackLink;
+}
+
+/**
+ Checks to see if a doubly-linked list is empty or not.
+
+ Checks to see if the doubly-linked list is empty. If the linked list contains
+ zero nodes, this function returns TRUE. Otherwise, it returns FALSE.
+
+ If ListHead is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+
+ @retval TRUE The linked list is empty.
+ @retval FALSE The linked list is not empty.
+
+**/
+BOOLEAN
+IsListEmpty (
+ IN CONST LIST_ENTRY *ListHead
+ )
+{
+ assert (ListHead != NULL);
+
+ return (BOOLEAN)(ListHead->ForwardLink == ListHead);
+}
+
+/**
+ Determines if a node in a doubly-linked list is the head node of a the same
+ doubly-linked list. This function is typically used to terminate a loop that
+ traverses all the nodes in a doubly-linked list starting with the head node.
+
+ Returns TRUE if Node is equal to List. Returns FALSE if Node is one of the
+ nodes in the doubly-linked list specified by List. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),
+ then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List and Node is not
+ equal to List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the head of the doubly-linked list pointed by List.
+ @retval FALSE Node is not the head of the doubly-linked list pointed by List.
+
+**/
+BOOLEAN
+IsNull (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return (BOOLEAN)(Node == List);
+}
+
+/**
+ Determines if a node the last node in a doubly-linked list.
+
+ Returns TRUE if Node is the last node in the doubly-linked list specified by
+ List. Otherwise, FALSE is returned. List must have been initialized with
+ INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the last node in the linked list.
+ @retval FALSE Node is not the last node in the linked list.
+
+**/
+BOOLEAN
+IsNodeAtEnd (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return (BOOLEAN)(!IsNull (List, Node) && (List->BackLink == Node));
+}
+
+/**
+ Removes a node from a doubly-linked list, and returns the node that follows
+ the removed node.
+
+ Removes the node Entry from a doubly-linked list. It is up to the caller of
+ this function to release the memory used by this node if that is required. On
+ exit, the node following Entry in the doubly-linked list is returned. If
+ Entry is the only node in the linked list, then the head node of the linked
+ list is returned.
+
+ If Entry is NULL, then ASSERT().
+ If Entry is the head node of an empty list, then ASSERT().
+ If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+ linked list containing Entry, including the Entry node, is greater than
+ or equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param Entry A pointer to a node in a linked list.
+
+ @return Entry.
+
+**/
+LIST_ENTRY *
+RemoveEntryList (
+ IN CONST LIST_ENTRY *Entry
+ )
+{
+ assert (!IsListEmpty (Entry));
+
+ Entry->ForwardLink->BackLink = Entry->BackLink;
+ Entry->BackLink->ForwardLink = Entry->ForwardLink;
+ return Entry->ForwardLink;
+}
+
diff --git a/BaseTools/Source/C/FCE/Expression.c b/BaseTools/Source/C/FCE/Expression.c
new file mode 100644
index 0000000000..34b310d97f
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Expression.c
@@ -0,0 +1,2367 @@
+/** @file
+
+ Utility functions for expression evaluation.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IfrParse.h"
+
+#define gEmptyString L""
+//
+// Global stack used to evaluate boolean expresions
+//
+EFI_HII_VALUE *mOpCodeScopeStack = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
+
+EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
+UINTN mExpressionEvaluationStackOffset = 0;
+
+EFI_HII_VALUE *mCurrentExpressionStack = NULL;
+EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
+EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
+
+EFI_HII_VALUE *mMapExpressionListStack = NULL;
+EFI_HII_VALUE *mMapExpressionListEnd = NULL;
+EFI_HII_VALUE *mMapExpressionListPointer = NULL;
+
+/**
+ Get Value for given Name from a NameValue Storage.
+
+ @param Storage The NameValue Storage.
+ @param Name The Name.
+ @param Value The retured Value.
+
+ @retval EFI_SUCCESS Value found for given Name.
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.
+
+**/
+EFI_STATUS
+GetValueByName (
+ IN FORMSET_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN OUT CHAR16 **Value
+ )
+{
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *Node;
+
+ *Value = NULL;
+
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+
+ if (FceStrCmp (Name, Node->Name) == 0) {
+ NewStringCpy (Value, Node->EditValue);
+ return EFI_SUCCESS;
+ }
+
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Grow size of the stack.
+
+ This is an internal function.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+
+ @retval EFI_SUCCESS Grow stack success.
+ @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
+
+**/
+EFI_STATUS
+GrowStack (
+ IN OUT EFI_HII_VALUE **Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ IN OUT EFI_HII_VALUE **StackEnd
+ )
+{
+ UINTN Size;
+ EFI_HII_VALUE *NewStack;
+
+ Size = EXPRESSION_STACK_SIZE_INCREMENT;
+ if (*StackPtr != NULL) {
+ Size = Size + (*StackEnd - *Stack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (*StackPtr != NULL) {
+ //
+ // Copy from Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ *Stack,
+ (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (*Stack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ *StackPtr = NewStack + (*StackPtr - *Stack);
+ *Stack = NewStack;
+ *StackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+ @param Data Data to push.
+
+ @retval EFI_SUCCESS Push stack success.
+
+**/
+EFI_STATUS
+PushStack (
+ IN OUT EFI_HII_VALUE **Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ IN OUT EFI_HII_VALUE **StackEnd,
+ IN EFI_HII_VALUE *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (*StackPtr >= *StackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowStack (Stack, StackPtr, StackEnd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
+ *StackPtr = *StackPtr + 1;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Pop an element from the stack.
+
+ @param Stack On input: old stack
+ @param StackPtr On input: old stack pointer; On output: new stack pointer
+ @param Data Data to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopStack (
+ IN EFI_HII_VALUE *Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ OUT EFI_HII_VALUE *Data
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (*StackPtr == Stack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ *StackPtr = *StackPtr - 1;
+ CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+ VOID
+ )
+{
+ mCurrentExpressionPointer = mCurrentExpressionStack;
+}
+
+
+/**
+ Push current expression onto the Stack
+
+ @param Pointer Pointer to current expression.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+ IN VOID *Pointer
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+ return PushStack (
+ &mCurrentExpressionStack,
+ &mCurrentExpressionPointer,
+ &mCurrentExpressionEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop current expression from the Stack
+
+ @param Pointer Pointer to current expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mCurrentExpressionStack,
+ &mCurrentExpressionPointer,
+ &Data
+ );
+
+ *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+ return Status;
+}
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+ VOID
+ )
+{
+ mMapExpressionListPointer = mMapExpressionListStack;
+}
+
+
+/**
+ Push the list of map expression onto the Stack
+
+ @param Pointer Pointer to the list of map expression to be pushed.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+ IN VOID *Pointer
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+ return PushStack (
+ &mMapExpressionListStack,
+ &mMapExpressionListPointer,
+ &mMapExpressionListEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop the list of map expression from the Stack
+
+ @param Pointer Pointer to the list of map expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mMapExpressionListStack,
+ &mMapExpressionListPointer,
+ &Data
+ );
+
+ *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+ return Status;
+}
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+ VOID
+ )
+{
+ mOpCodeScopeStackPointer = mOpCodeScopeStack;
+}
+
+
+/**
+ Push an Operand onto the Stack
+
+ @param Operand Operand to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushScope (
+ IN UINT8 Operand
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Data.Value.u8 = Operand;
+
+ return PushStack (
+ &mOpCodeScopeStack,
+ &mOpCodeScopeStackPointer,
+ &mOpCodeScopeStackEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop an Operand from the Stack
+
+ @param Operand Operand to pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PopScope (
+ OUT UINT8 *Operand
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mOpCodeScopeStack,
+ &mOpCodeScopeStackPointer,
+ &Data
+ );
+
+ *Operand = Data.Value.u8;
+
+ return Status;
+}
+
+
+/**
+ Push an Expression value onto the Stack
+
+ @param Value Expression value to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushExpression (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ return PushStack (
+ &mExpressionEvaluationStack,
+ &mExpressionEvaluationStackPointer,
+ &mExpressionEvaluationStackEnd,
+ Value
+ );
+}
+
+
+/**
+ Pop an Expression value from the stack.
+
+ @param Value Expression value to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopExpression (
+ OUT EFI_HII_VALUE *Value
+ )
+{
+ return PopStack (
+ mExpressionEvaluationStack + mExpressionEvaluationStackOffset,
+ &mExpressionEvaluationStackPointer,
+ Value
+ );
+}
+
+/**
+ Get current stack offset from stack start.
+
+ @return Stack offset to stack start.
+**/
+UINTN
+SaveExpressionEvaluationStackOffset (
+ )
+{
+ UINTN TempStackOffset;
+ TempStackOffset = mExpressionEvaluationStackOffset;
+ mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;
+ return TempStackOffset;
+}
+
+/**
+ Restore stack offset based on input stack offset
+
+ @param StackOffset Offset to stack start.
+
+**/
+VOID
+RestoreExpressionEvaluationStackOffset (
+ UINTN StackOffset
+ )
+{
+ mExpressionEvaluationStackOffset = StackOffset;
+}
+
+
+/**
+ Search a Question in Form scope using its QuestionId.
+
+ @param Form The form which contains this Question.
+ @param QuestionId Id of this Question.
+
+ @retval Pointer The Question.
+ @retval NULL Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion2 (
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 QuestionId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ if (QuestionId == 0) {
+ //
+ // The value of zero is reserved
+ //
+ return NULL;
+ }
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ if (Question->QuestionId == QuestionId) {
+ return Question;
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Search a Question in Formset scope using its QuestionId.
+
+ @param FormSet The formset which contains this form.
+ @param Form The form which contains this Question.
+ @param QuestionId Id of this Question.
+
+ @retval Pointer The Question.
+ @retval NULL Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 QuestionId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ //
+ // Search in the form scope first
+ //
+ Question = IdToQuestion2 (Form, QuestionId);
+ if (Question != NULL) {
+ return Question;
+ }
+
+ //
+ // Search in the formset scope
+ //
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ Question = IdToQuestion2 (Form, QuestionId);
+ if (Question != NULL) {
+ return Question;
+ }
+
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Get Expression given its RuleId.
+
+ @param Form The form which contains this Expression.
+ @param RuleId Id of this Expression.
+
+ @retval Pointer The Expression.
+ @retval NULL Specified Expression not found in the form.
+
+**/
+FORM_EXPRESSION *
+RuleIdToExpression (
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT8 RuleId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ while (!IsNull (&Form->ExpressionListHead, Link)) {
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+
+ if ((Expression->Type == EFI_HII_EXPRESSION_RULE) && (Expression->RuleId == RuleId)) {
+ return Expression;
+ }
+
+ Link = GetNextNode (&Form->ExpressionListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Convert the input Unicode character to upper.
+
+ @param String Th Unicode character to be converted.
+
+**/
+VOID
+IfrStrToUpper (
+ IN CHAR16 *String
+ )
+{
+ while (*String != 0) {
+ if ((*String >= 'a') && (*String <= 'z')) {
+ *String = (UINT16) ((*String) & ((UINT16) ~0x20));
+ }
+ String++;
+ }
+}
+
+/**
+ Evaluate opcode EFI_IFR_TO_STRING.
+
+ @param FormSet Formset which contains this opcode.
+ @param Format String format in EFI_IFR_TO_STRING.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToString (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Format,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *PrintFormat;
+ CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
+ UINTN BufferSize;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (Value.Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
+ switch (Format) {
+ case EFI_IFR_STRING_UNSIGNED_DEC:
+ case EFI_IFR_STRING_SIGNED_DEC:
+ PrintFormat = L"%ld";
+ break;
+
+ case EFI_IFR_STRING_LOWERCASE_HEX:
+ PrintFormat = L"%lx";
+ break;
+
+ case EFI_IFR_STRING_UPPERCASE_HEX:
+ PrintFormat = L"%lX";
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
+ break;
+
+ case EFI_IFR_TYPE_STRING:
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+ return EFI_SUCCESS;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (String, FormSet->HiiHandle);
+ return EFI_SUCCESS;
+}
+
+/**
+ Evaluate opcode EFI_IFR_TO_UINT.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToUint (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String;
+ CHAR16 *StringPtr;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Value.Type >= EFI_IFR_TYPE_OTHER) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+ if (Value.Type == EFI_IFR_TYPE_STRING) {
+ String = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ IfrStrToUpper (String);
+ StringPtr = StrStr (String, L"0X");
+ if (StringPtr != NULL) {
+ //
+ // Hex string
+ //
+ Result->Value.u64 = FceStrHexToUint64 (String);
+ } else {
+ //
+ // decimal string
+ //
+ Result->Value.u64 = FceStrDecimalToUint64 (String);
+ }
+ FreePool (String);
+ } else {
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_CATENATE.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrCatenate (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Index;
+ CHAR16 *StringPtr;
+ UINTN Size;
+
+ //
+ // String[0] - The second string
+ // String[1] - The first string
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ StringPtr = NULL;
+ Status = EFI_SUCCESS;
+
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Size = FceStrSize (String[0]);
+ StringPtr= AllocatePool (FceStrSize (String[1]) + Size);
+ ASSERT (StringPtr != NULL);
+ StrCpy (StringPtr, String[1]);
+ StrCat (StringPtr, String[0]);
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+ if (StringPtr != NULL) {
+ FreePool (StringPtr);
+ }
+
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_MATCH.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMatch (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Index;
+
+ //
+ // String[0] - The string to search
+ // String[1] - pattern
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String [Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_BOOLEAN;
+ Result->Value.b = MetaiMatch (String[0], String[1]);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_FIND.
+
+ @param FormSet Formset which contains this opcode.
+ @param Format Case sensitive or insensitive.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrFind (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Format,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Base;
+ CHAR16 *StringPtr;
+ UINTN Index;
+
+ if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Base = (UINTN) Value.Value.u64;
+
+ //
+ // String[0] - sub-string
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
+ //
+ // Case insensitive, convert both string to upper case
+ //
+ IfrStrToUpper (String[Index]);
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ if (Base >= FceStrLen (String[1])) {
+ Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
+ } else {
+ StringPtr = StrStr (String[1] + Base, String[0]);
+ Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
+ }
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_MID.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMid (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String;
+ UINTN Base;
+ UINTN Length;
+ CHAR16 *SubString;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Length = (UINTN) Value.Value.u64;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Base = (UINTN) Value.Value.u64;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ return EFI_UNSUPPORTED;
+ }
+ String = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((Length == 0) || (Base >= FceStrLen (String))) {
+ SubString = gEmptyString;
+ } else {
+ SubString = String + Base;
+ if ((Base + Length) < FceStrLen (String)) {
+ SubString[Length] = L'\0';
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+ FreePool (String);
+
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_TOKEN.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToken (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Count;
+ CHAR16 *Delimiter;
+ CHAR16 *SubString;
+ CHAR16 *StringPtr;
+ UINTN Index;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Count = (UINTN) Value.Value.u64;
+
+ //
+ // String[0] - Delimiter
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Delimiter = String[0];
+ SubString = String[1];
+ while (Count > 0) {
+ SubString = StrStr (SubString, Delimiter);
+ if (SubString != NULL) {
+ //
+ // Skip over the delimiter
+ //
+ SubString = SubString + FceStrLen (Delimiter);
+ } else {
+ break;
+ }
+ Count--;
+ }
+
+ if (SubString == NULL) {
+ //
+ // nth delimited sub-string not found, push an empty string
+ //
+ SubString = gEmptyString;
+ } else {
+ //
+ // Put a NULL terminator for nth delimited sub-string
+ //
+ StringPtr = StrStr (SubString, Delimiter);
+ if (StringPtr != NULL) {
+ *StringPtr = L'\0';
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_SPAN.
+
+ @param FormSet Formset which contains this opcode.
+ @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrSpan (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Flags,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ CHAR16 *Charset;
+ UINTN Base;
+ UINTN Index;
+ CHAR16 *StringPtr;
+ BOOLEAN Found;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Base = (UINTN) Value.Value.u64;
+
+ //
+ // String[0] - Charset
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String [Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ if (Base >= FceStrLen (String[1])) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Found = FALSE;
+ StringPtr = String[1] + Base;
+ Charset = String[0];
+ while (*StringPtr != 0 && !Found) {
+ Index = 0;
+ while (Charset[Index] != 0) {
+ if ((*StringPtr >= Charset[Index]) && (*StringPtr <= Charset[Index + 1])) {
+ if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
+ Found = TRUE;
+ break;
+ }
+ } else {
+ if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
+ Found = TRUE;
+ break;
+ }
+ }
+ //
+ // Skip characters pair representing low-end of a range and high-end of a range
+ //
+ Index += 2;
+ }
+
+ if (!Found) {
+ StringPtr++;
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Result->Value.u64 = StringPtr - String[1];
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+ @param Value HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ UINT64 Temp;
+
+ Temp = 0;
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Temp = Value->Value.u8;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Temp = Value->Value.u16;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Temp = Value->Value.u32;
+ break;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ Temp = Value->Value.b;
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ Temp = Value->Value.u32 & 0xffffff;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ Temp = Value->Value.u32;
+ break;
+
+ default:
+ return;
+ }
+
+ Value->Value.u64 = Temp;
+}
+
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+ @param FormSet The pointer to the Formset.
+
+ @retval EFI_INVALID_PARAMETER Could not perform compare on two values.
+ @retval 0 Two operators equal.
+ @return Positive value if Value1 is greater than Value2.
+ @retval Negative value if Value1 is less than Value2.
+
+**/
+INTN
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ INTN Result;
+ INT64 Temp64;
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+
+ if ((Value1->Type >= EFI_IFR_TYPE_OTHER) || (Value2->Type >= EFI_IFR_TYPE_OTHER) ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Value1->Type == EFI_IFR_TYPE_STRING) || (Value2->Type == EFI_IFR_TYPE_STRING) ) {
+ if (Value1->Type != Value2->Type) {
+ //
+ // Both Operator should be type of String
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) {
+ //
+ // StringId 0 is reserved
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Value1->Value.string == Value2->Value.string) {
+ return 0;
+ }
+
+ Str1 = GetToken (Value1->Value.string, FormSet->UnicodeBinary);
+ if (Str1 == NULL) {
+ //
+ // String not found
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Str2 = GetToken (Value2->Value.string, FormSet->UnicodeBinary);
+ if (Str2 == NULL) {
+ FreePool (Str1);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Result = FceStrCmp (Str1, Str2);
+
+ FreePool (Str1);
+ FreePool (Str2);
+
+ return Result;
+ }
+
+ //
+ // Take remain types(integer, boolean, date/time) as integer
+ //
+ Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
+ if (Temp64 > 0) {
+ Result = 1;
+ } else if (Temp64 < 0) {
+ Result = -1;
+ } else {
+ Result = 0;
+ }
+
+ return Result;
+}
+
+/**
+ Tell whether this Operand is an constant Expression or not
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Expression OpCode.
+ @retval FALSE Not an Expression OpCode.
+
+**/
+BOOLEAN
+IsConstantExpressionOpCode (
+ IN UINT8 Operand
+ )
+{
+ if ((Operand == EFI_IFR_EQ_ID_VAL_OP) ||
+ (Operand == EFI_IFR_EQ_ID_ID_OP) ||
+ (Operand == EFI_IFR_EQ_ID_VAL_LIST_OP )||
+ (Operand == EFI_IFR_QUESTION_REF1_OP) ||
+ (Operand == EFI_IFR_QUESTION_REF2_OP) ||
+ (Operand == EFI_IFR_QUESTION_REF3_OP) ||
+ (Operand == EFI_IFR_THIS_OP ) ||
+ (Operand == EFI_IFR_SECURITY_OP) ||
+ (Operand == EFI_IFR_GET_OP) ||
+ (Operand == EFI_IFR_SET_OP)
+ ) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Update the HiiValue of question from its variable.
+
+ @param FormSet FormSet associated with this expression.
+ @param Question The pointer to the Question
+
+ @return EFI_SUCCESS
+ @return EFI_NOT_FOUND
+**/
+EFI_STATUS
+UpdateHiiValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+ EFI_HII_VALUE *HiiValue;
+
+ Status = EFI_SUCCESS;
+ HiiValue = &Question->HiiValue;
+
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ if (Question->QuestionReferToBitField) {
+ GetBitsQuestionValue (Question, VarBuffer, &HiiValue->Value.u32);
+ } else {
+ CopyMem (&HiiValue->Value.u64, VarBuffer, Question->StorageWidth);
+ }
+ return Status;
+}
+/**
+ Evaluate the result of a HII expression.
+
+ If Expression is NULL, then ASSERT.
+
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+ @param Expression Expression to be evaluated.
+ @param ConstantExpression The pointer to the flag of constant expression. If constant, will return TRUE.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
+ could not be found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_EXPRESSION *Expression,
+ IN OUT BOOLEAN *ConstantExpression
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EXPRESSION_OPCODE *OpCode;
+ FORM_BROWSER_STATEMENT *Question;
+ FORM_BROWSER_STATEMENT *Question2;
+ UINT16 Index;
+ EFI_HII_VALUE Data1;
+ EFI_HII_VALUE Data2;
+ EFI_HII_VALUE Data3;
+ FORM_EXPRESSION *RuleExpression;
+ EFI_HII_VALUE *Value;
+ INTN Result;
+ CHAR16 *StrPtr;
+ UINT32 TempValue;
+ LIST_ENTRY *SubExpressionLink;
+ FORM_EXPRESSION *SubExpression;
+ UINTN StackOffset;
+ UINTN TempLength;
+ CHAR16 TempStr[5];
+ UINT8 DigitUint8;
+ UINT8 *TempBuffer;
+
+ //
+ // Save current stack offset.
+ //
+ StackOffset = SaveExpressionEvaluationStackOffset ();
+
+ ASSERT (Expression != NULL);
+ Expression->Result.Type = EFI_IFR_TYPE_OTHER;
+
+ Link = GetFirstNode (&Expression->OpCodeListHead);
+ while (!IsNull (&Expression->OpCodeListHead, Link)) {
+ OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+
+ Link = GetNextNode (&Expression->OpCodeListHead, Link);
+
+ ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
+ ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
+ ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
+
+ Value = &Data3;
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Status = EFI_SUCCESS;
+
+ //
+ // Check whether it is a constant expression or not
+ //
+ if (*ConstantExpression) {
+ *ConstantExpression = IsConstantExpressionOpCode (OpCode->Operand);
+ }
+
+ switch (OpCode->Operand) {
+ //
+ // Built-in functions
+ //
+ case EFI_IFR_EQ_ID_VAL_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, FormSet);
+ if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_EQ_ID_ID_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
+ if (Question2 == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ UpdateHiiValue (FormSet, Question2);
+ Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet);
+ if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_EQ_ID_VAL_LIST_OP:
+
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ Value->Value.b = FALSE;
+ for (Index =0; Index < OpCode->ListLength; Index++) {
+ if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
+ Value->Value.b = TRUE;
+ break;
+ }
+ }
+ break;
+
+ case EFI_IFR_DUP_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PushExpression (Value);
+ break;
+
+ case EFI_IFR_QUESTION_REF1_OP:
+ case EFI_IFR_THIS_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ Value = &Question->HiiValue;
+ break;
+
+ case EFI_IFR_SECURITY_OP:
+ //
+ // Do nothing, as no need for static scaning
+ //
+ break;
+
+ case EFI_IFR_GET_OP:
+ //
+ // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
+ //
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Value->Value.u8 = 0;
+ if (OpCode->VarStorage != NULL) {
+ switch (OpCode->VarStorage->Type) {
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // Get value from Buffer
+ //
+ Value->Type = OpCode->ValueType;
+ CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // Get value from Buffer
+ //
+ if (OpCode->VarStorage->NewEfiVarstore) {
+ Value->Type = OpCode->ValueType;
+ CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
+ } else {
+ CopyMem (&Value->Value, OpCode->VarStorage->Buffer, OpCode->ValueWidth);
+ }
+
+
+ break;
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
+ //
+ // Get value from string except for STRING value.
+ //
+ Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (StrPtr != NULL);
+ TempLength = FceStrLen (StrPtr);
+ if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
+ Value->Type = OpCode->ValueType;
+ TempBuffer = (UINT8 *) &Value->Value;
+ ZeroMem (TempStr, sizeof (TempStr));
+ for (Index = 0; Index < TempLength; Index ++) {
+ TempStr[0] = StrPtr[TempLength - Index - 1];
+ DigitUint8 = (UINT8) FceStrHexToUint64 (TempStr);
+ if ((Index & 1) == 0) {
+ TempBuffer [Index/2] = DigitUint8;
+ } else {
+ TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
+ }
+ }
+ }
+ free (StrPtr);
+ StrPtr = NULL;
+ }
+ }
+ break;
+ default:
+ //
+ // Not recognize storage.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ }
+
+ break;
+
+ case EFI_IFR_QUESTION_REF3_OP:
+ if (OpCode->DevicePath == 0) {
+ //
+ // EFI_IFR_QUESTION_REF3
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // push the questions' value on to the expression stack
+ //
+ Value = &Question->HiiValue;
+ } else {
+ //
+ // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
+ // since it is impractical to evaluate the value of a Question in another
+ // Hii Package list.
+ //
+ ZeroMem (Value, sizeof (EFI_HII_VALUE));
+ }
+ break;
+
+ case EFI_IFR_RULE_REF_OP:
+ //
+ // Find expression for this rule
+ //
+ RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
+ if (RuleExpression == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Evaluate this rule expression
+ //
+ Status = EvaluateExpression (FormSet, Form, RuleExpression, ConstantExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Value = &RuleExpression->Result;
+ break;
+
+ case EFI_IFR_STRING_REF1_OP:
+ Value->Type = EFI_IFR_TYPE_STRING;
+ Value->Value.string = OpCode->Value.Value.string;
+ break;
+
+ //
+ // Constant
+ //
+ case EFI_IFR_TRUE_OP:
+ case EFI_IFR_FALSE_OP:
+ case EFI_IFR_ONE_OP:
+ case EFI_IFR_ONES_OP:
+ case EFI_IFR_UINT8_OP:
+ case EFI_IFR_UINT16_OP:
+ case EFI_IFR_UINT32_OP:
+ case EFI_IFR_UINT64_OP:
+ case EFI_IFR_UNDEFINED_OP:
+ case EFI_IFR_VERSION_OP:
+ case EFI_IFR_ZERO_OP:
+ Value = &OpCode->Value;
+ break;
+
+ //
+ // unary-op
+ //
+ case EFI_IFR_LENGTH_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = FceStrLen (StrPtr);
+ FreePool (StrPtr);
+ break;
+
+ case EFI_IFR_NOT_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) (!Value->Value.b);
+ break;
+
+ case EFI_IFR_QUESTION_REF2_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Value = &Question->HiiValue;
+ break;
+
+ case EFI_IFR_STRING_REF2_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_STRING;
+ StrPtr = GetToken (Value->Value.u16, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ //
+ // If String not exit, push an empty string
+ //
+ //Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
+ } else {
+ Index = (UINT16) Value->Value.u64;
+ Value->Value.string = Index;
+ FreePool (StrPtr);
+ }
+ break;
+
+ case EFI_IFR_TO_BOOLEAN_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Convert an expression to a Boolean
+ //
+ if (Value->Type <= EFI_IFR_TYPE_DATE) {
+ //
+ // When converting from an unsigned integer, zero will be converted to
+ // FALSE and any other value will be converted to TRUE.
+ //
+ Value->Value.b = (BOOLEAN) (Value->Value.u64 != 0);
+
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ } else if (Value->Type == EFI_IFR_TYPE_STRING) {
+ //
+ // When converting from a string, if case-insensitive compare
+ // with "true" is True, then push True. If a case-insensitive compare
+ // with "false" is True, then push False. Otherwise, push Undefined.
+ //
+ StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ IfrStrToUpper (StrPtr);
+ if (FceStrCmp (StrPtr, L"TRUE") == 0){
+ Value->Value.b = TRUE;
+ } else if (FceStrCmp (StrPtr, L"FALSE") == 0) {
+ Value->Value.b = FALSE;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ FreePool (StrPtr);
+ goto Done;
+ }
+ FreePool (StrPtr);
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ }
+ break;
+
+ case EFI_IFR_TO_STRING_OP:
+ //Status = IfrToString (FormSet, OpCode->Format, Value);
+ break;
+
+ case EFI_IFR_TO_UINT_OP:
+ Status = IfrToUint (FormSet, Value);
+ break;
+
+ case EFI_IFR_TO_LOWER_OP:
+ case EFI_IFR_TO_UPPER_OP:
+
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value->Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ //
+ // Do nothing here, as these two Opcode are to change or update the String Package
+ //
+ FreePool (StrPtr);
+ break;
+
+ case EFI_IFR_BITWISE_NOT_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type > EFI_IFR_TYPE_DATE) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = ~Value->Value.u64;
+ break;
+
+ case EFI_IFR_SET_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Data1.Type = EFI_IFR_TYPE_BOOLEAN;
+ Data1.Value.b = FALSE;
+ //
+ // Not support SetOpcode for static scaning
+ //
+ if (OpCode->VarStorage != NULL) {
+ switch (OpCode->VarStorage->Type) {
+
+ case EFI_IFR_VARSTORE_OP:
+ CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
+ Data1.Value.b = TRUE;
+ break;
+ case EFI_IFR_VARSTORE_EFI_OP:
+ if (OpCode->VarStorage->NewEfiVarstore) {
+ CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
+ Data1.Value.b = TRUE;
+ } else {
+ CopyMem (OpCode->VarStorage->Buffer, &Value->Value, OpCode->ValueWidth);
+ Data1.Value.b = TRUE;
+ }
+ break;
+ case EFI_HII_VARSTORE_NAME_VALUE:
+
+ break;
+ break;
+ default:
+ //
+ // Not recognize storage.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ break;
+ }
+ Value = &Data1;
+ }
+ break;
+
+ //
+ // binary-op
+ //
+ case EFI_IFR_ADD_OP:
+ case EFI_IFR_SUBTRACT_OP:
+ case EFI_IFR_MULTIPLY_OP:
+ case EFI_IFR_DIVIDE_OP:
+ case EFI_IFR_MODULO_OP:
+ case EFI_IFR_BITWISE_AND_OP:
+ case EFI_IFR_BITWISE_OR_OP:
+ case EFI_IFR_SHIFT_LEFT_OP:
+ case EFI_IFR_SHIFT_RIGHT_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data2.Type > EFI_IFR_TYPE_DATE) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data1.Type > EFI_IFR_TYPE_DATE) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+
+ switch (OpCode->Operand) {
+ case EFI_IFR_ADD_OP:
+ Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
+ break;
+
+ case EFI_IFR_SUBTRACT_OP:
+ Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
+ break;
+
+ case EFI_IFR_MULTIPLY_OP:
+ Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
+ break;
+
+ case EFI_IFR_DIVIDE_OP:
+ Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
+ break;
+
+ case EFI_IFR_MODULO_OP:
+ DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);
+ Value->Value.u64 = TempValue;
+ break;
+
+ case EFI_IFR_BITWISE_AND_OP:
+ Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
+ break;
+
+ case EFI_IFR_BITWISE_OR_OP:
+ Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
+ break;
+
+ case EFI_IFR_SHIFT_LEFT_OP:
+ Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
+ break;
+
+ case EFI_IFR_SHIFT_RIGHT_OP:
+ Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_IFR_AND_OP:
+ case EFI_IFR_OR_OP:
+ //
+ // Two Boolean operator
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (OpCode->Operand == EFI_IFR_AND_OP) {
+ Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
+ } else {
+ Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
+ }
+ break;
+
+ case EFI_IFR_EQUAL_OP:
+ case EFI_IFR_NOT_EQUAL_OP:
+ case EFI_IFR_GREATER_EQUAL_OP:
+ case EFI_IFR_GREATER_THAN_OP:
+ case EFI_IFR_LESS_EQUAL_OP:
+ case EFI_IFR_LESS_THAN_OP:
+ //
+ // Compare two integer, string, boolean or date/time
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if ((Data2.Type > EFI_IFR_TYPE_BOOLEAN) && (Data2.Type != EFI_IFR_TYPE_STRING)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Result = CompareHiiValue (&Data1, &Data2, FormSet);
+ if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ switch (OpCode->Operand) {
+ case EFI_IFR_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_NOT_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_GREATER_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_GREATER_THAN_OP:
+ Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_LESS_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_LESS_THAN_OP:
+ Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_IFR_MATCH_OP:
+ Status = IfrMatch (FormSet, Value);
+ break;
+
+ case EFI_IFR_CATENATE_OP:
+ Status = IfrCatenate (FormSet, Value);
+ break;
+
+ //
+ // ternary-op
+ //
+ case EFI_IFR_CONDITIONAL_OP:
+ //
+ // Pop third expression from the expression stack
+ //
+ Status = PopExpression (&Data3);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop second expression from the expression stack
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop first expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Data1.Value.b) {
+ Value = &Data3;
+ } else {
+ Value = &Data2;
+ }
+ break;
+
+ case EFI_IFR_FIND_OP:
+ Status = IfrFind (FormSet, OpCode->Format, Value);
+ break;
+
+ case EFI_IFR_MID_OP:
+ Status = IfrMid (FormSet, Value);
+ break;
+
+ case EFI_IFR_TOKEN_OP:
+ Status = IfrToken (FormSet, Value);
+ break;
+
+ case EFI_IFR_SPAN_OP:
+ Status = IfrSpan (FormSet, OpCode->Flags, Value);
+ break;
+
+ case EFI_IFR_MAP_OP:
+ //
+ // Pop the check value
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check MapExpression list is valid.
+ //
+ if (OpCode->MapExpressionList.ForwardLink == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Go through map expression list.
+ //
+ SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+ while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ //
+ // Evaluate the first expression in this pair.
+ //
+ Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Compare the expression value with current value
+ //
+ if (CompareHiiValue (&Data1, &SubExpression->Result, FormSet) == 0) {
+ //
+ // Try get the map value.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Value = &SubExpression->Result;
+ break;
+ }
+ //
+ // Skip the second expression on this pair.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Goto the first expression on next pair.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ }
+
+ //
+ // No map value is found.
+ //
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Value->Value.u8 = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PushExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Pop the final result from expression stack
+ //
+ Value = &Data1;
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // After evaluating an expression, there should be only one value left on the expression stack
+ //
+ if (PopExpression (Value) != EFI_ACCESS_DENIED) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ RestoreExpressionEvaluationStackOffset (StackOffset);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
+ }
+
+ return Status;
+}
diff --git a/BaseTools/Source/C/FCE/Fce.c b/BaseTools/Source/C/FCE/Fce.c
new file mode 100644
index 0000000000..1845c508b5
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Fce.c
@@ -0,0 +1,6449 @@
+/** @file
+
+ FCE is a tool which enables developers to retrieve and change HII configuration ("Setup")
+ data in Firmware Device files (".fd" files).
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+
+#ifndef __GNUC__
+#define COPY_STR "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR "del \"%s\" > NUL"
+#else
+#define COPY_STR "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR "rm -r \"%s\" > /dev/null"
+#define DEL_STR "rm \"%s\" > /dev/null"
+#endif
+
+//
+// Utility global variables
+//
+OPERATION_TYPE Operations;
+
+CHAR8 mInputFdName[MAX_FILENAME_LEN];
+CHAR8 mOutputFdName[MAX_FILENAME_LEN];
+CHAR8 mOutTxtName[MAX_FILENAME_LEN];
+CHAR8 mSetupTxtName[MAX_FILENAME_LEN];
+
+CHAR8* mUtilityFilename = NULL;
+UINT32 mEfiVariableAddr = 0;
+
+UQI_PARAM_LIST *mUqiList = NULL;
+UQI_PARAM_LIST *mLastUqiList = NULL;
+LIST_ENTRY mVarListEntry;
+LIST_ENTRY mBfvVarListEntry;
+LIST_ENTRY mAllVarListEntry;
+LIST_ENTRY mFormSetListEntry;
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+
+CHAR8* mGuidToolDefinition = "GuidToolDefinitionConf.ini";
+
+//
+//gFfsArray is used to store all the FFS informations of Fd
+//
+G_EFI_FD_INFO gEfiFdInfo;
+//
+//mMultiPlatformParam is used to store the structures about multi-platform support
+//
+MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+
+UINT32 mFormSetOrderRead;
+UINT32 mFormSetOrderParse;
+
+CHAR8 mFullGuidToolDefinitionDir[_MAX_PATH];
+
+CHAR8 *mFvNameGuidString = NULL;
+
+/**
+ Check the revision of BfmLib. If not matched, return an error.
+
+ @retval EFI_SUCCESS If revision matched, return EFI_SUCCESS.
+ @retval EFI_UNSUPPORTED Other cases.
+**/
+static
+EFI_STATUS
+CheckBfmLibRevision (
+ VOID
+ )
+{
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ CHAR8 *TempSystemCommand;
+ CHAR8 *Revision;
+ FILE *FileHandle;
+ CHAR8 RevisionStr[_MAX_BUILD_VERSION];
+ UINT32 Len;
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ TempSystemCommand = NULL;
+ Revision = "Revision.txt";
+
+ memset (RevisionStr, 0, _MAX_BUILD_VERSION);
+
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "BfmLib -v > %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (Revision) + 1
+ );
+ if (SystemCommand == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -v > %s",
+ Revision
+ );
+
+ if (mFullGuidToolDefinitionDir[0] != 0) {
+ TempSystemCommand = SystemCommand;
+ SystemCommand = malloc (
+ strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (SystemCommandFormatString) + strlen (Revision) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ free (TempSystemCommand);
+ return EFI_UNSUPPORTED;
+ }
+ strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+ strcat (SystemCommand, OS_SEP_STR);
+ strcat (SystemCommand, TempSystemCommand);
+ free (TempSystemCommand);
+ }
+
+ system (SystemCommand);
+ free (SystemCommand);
+ FileHandle = fopen (Revision, "r");
+ if (FileHandle == NULL) {
+ printf ("Error. Read the revision file of BfmLib failed.\n");
+ return EFI_ABORTED;
+ }
+ fgets(RevisionStr, _MAX_BUILD_VERSION, FileHandle);
+ Len = strlen(RevisionStr);
+ if (RevisionStr[Len - 1] == '\n') {
+ RevisionStr[Len - 1] = 0;
+ }
+ fclose (FileHandle);
+ remove (Revision);
+
+ if (strlen (RevisionStr) > _MAX_BUILD_VERSION - 1) {
+ printf ("The revision string is too long");
+ return EFI_UNSUPPORTED;
+ }
+ if (strcmp (RevisionStr, __BUILD_VERSION) == 0) {
+ return EFI_SUCCESS;
+ }
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Transfer the Ascii string to the Dec Number
+
+ @param InStr The Ascii string.
+
+ @retval DecNum Return the Dec number.
+**/
+static
+UINT64
+StrToDec (
+ IN CHAR8 *InStr
+ )
+{
+ UINT8 Index;
+ UINTN DecNum;
+ UINTN Temp;
+
+ Index = 0;
+ DecNum = 0;
+ Temp = 0;
+
+ if (InStr == NULL) {
+ return (UINT64)-1;
+ }
+ while (Index < strlen (InStr)) {
+
+ if ((*(InStr + Index) >= '0') && (*(InStr + Index) <= '9')) {
+ Temp = *(InStr + Index) - '0';
+ } else if ((*(InStr + Index) >= 'a') && (*(InStr + Index) <= 'f')) {
+ Temp = *(InStr + Index) - 'a' + 10;
+ } else if ((*(InStr + Index) >= 'A') && (*(InStr + Index) <= 'F')) {
+ Temp = *(InStr + Index) - 'A' + 10;
+ }
+ DecNum = DecNum + Temp * (UINTN) pow (16, strlen (InStr) - Index - 1);
+ Index++;
+ }
+ return DecNum;
+}
+/**
+ Check whether there are some errors in uqi parameters of One_of
+
+ @param Question The pointer to the question Node.
+ @param UqiValue The value of One_of.
+
+ @retval TRUE If existed error, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+static
+BOOLEAN
+CheckOneOfParamError (
+ IN CONST FORM_BROWSER_STATEMENT *Question,
+ IN UINT64 UqiValue
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ UINT64 Value;
+
+ Link = NULL;
+ Option = NULL;
+ Value = 0;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ Value = 0;
+ CopyMem (&Value, &Option->Value.Value.u64, Question->StorageWidth);
+ if (Value == UqiValue) {
+ return FALSE;
+ }
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether there are some errors in uqi parameters of Orderlist
+
+ @param HiiObjList The pointer to the Hii Object Node.
+ @param UqiValue The pointer to the Uqi parameter.
+
+ @retval TRUE If existed error, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+static
+BOOLEAN
+CheckOrderParamError (
+ IN CONST FORM_BROWSER_STATEMENT *Question,
+ IN CHAR8 *UqiValue
+ )
+{
+ UINT8 MaxNum;
+ MaxNum = UqiValue[0];
+
+ if (MaxNum != (UINT8)(Question->MaxContainers)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Writes a Unicode string
+
+ @param Package A pointer to the Unicode string.
+
+ @return NULL
+**/
+static
+VOID
+WriteUnicodeStr (
+ IN CHAR16 *pcString
+ )
+{
+ UINTN Index;
+
+ if (pcString == NULL) {
+ return;
+ }
+
+ for (Index = 0; pcString[Index] != 0; Index++) {
+ printf("%c", pcString[Index] & 0x00FF);
+ }
+}
+
+/**
+ Parse and set the quick configure information by the command line.
+
+ Read the UQI Config information from command line directly, and then compare it with the value in VarList.
+ Update the Update flag in Varlist.
+
+ @param CurUqiList The pointer to the current uqi
+ @param DefaultId The default Id.
+ @param PlatformId The platform Id.
+ @param CurQuestion The pointer to the matched question
+
+ @retval EFI_SUCCESS It was complete successfully
+ @retval EFI_UNSUPPORTED Update a read-only value
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+SetUqiParametersWithQuestion (
+ IN UQI_PARAM_LIST *CurUqiList,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN FORM_BROWSER_STATEMENT *CurQuestion
+ )
+{
+ FORMSET_STORAGE *VarList;
+ BOOLEAN IsFound;
+ UINT8 *ValueAddrOfVar;
+ UINT16 Index;
+ UINT64 QuestionValue;
+ UINT64 UqiValue;
+ EFI_STATUS Status;
+ CHAR8 *ErrorStr;
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ UINT64 CurValue;
+
+ VarList = NULL;
+ Index = 0;
+ ValueAddrOfVar = NULL;
+ QuestionValue = 0;
+ UqiValue = 0;
+ ErrorStr = NULL;
+ Status = EFI_SUCCESS;
+ FormSet = NULL;
+ FormSetLink = NULL;
+ CurValue = 0;
+
+ //
+ // Search the Variable List by VarStoreId and Offset
+ //
+ IsFound = FALSE;
+ FormSetLink = GetFirstNode (&mFormSetListEntry);
+ while (!IsNull (&mFormSetListEntry, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ Status = SearchVarStorage (
+ CurQuestion,
+ NULL,
+ CurQuestion->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **) &ValueAddrOfVar,
+ &VarList
+ );
+
+ if (!EFI_ERROR (Status)) {
+ IsFound = TRUE;
+ break;
+ }
+ FormSetLink = GetNextNode (&mFormSetListEntry, FormSetLink);
+ }
+
+ if (!IsFound) {
+ if (CurUqiList->Header.ScriptsLine == 0) {
+ printf ("Error. The question in the command line doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n");
+ } else {
+ printf ("Error. The question in the line %d of script doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n", CurUqiList->Header.ScriptsLine);
+ }
+ return EFI_ABORTED;
+ }
+
+ //
+ // Check the length of variable value
+ //
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)&QuestionValue);
+ } else {
+ switch (CurQuestion->StorageWidth) {
+
+ case sizeof (UINT8):
+ QuestionValue = *(UINT8 *)ValueAddrOfVar;
+ break;
+
+ case sizeof (UINT16):
+ QuestionValue = *(UINT16 *)ValueAddrOfVar;
+ break;
+
+ case sizeof (UINT32):
+ QuestionValue = *(UINT32 *)ValueAddrOfVar;
+ break;
+
+ case sizeof (UINT64):
+ QuestionValue = *(UINT64 *)ValueAddrOfVar;
+ break;
+
+ default:
+ //
+ // The storage width of ORDERED_LIST may not be any type above.
+ //
+ ;
+ break;
+ }
+ }
+ UqiValue = *(UINT64 *)CurUqiList->Header.Value;
+ CurUqiList->SameOrNot = TRUE;
+
+ //
+ // Check and set the checkbox value
+ //
+ if (CurQuestion->Operand == EFI_IFR_CHECKBOX_OP) {
+ if ((UqiValue != 0) && (UqiValue != 1)) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated value of CHECKBOX 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ } else {
+ if (QuestionValue != UqiValue) {
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy (
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ }
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ if (CurQuestion->Operand == EFI_IFR_STRING_OP) {
+ if ((FceStrLen((wchar_t *)CurUqiList->Header.Value) + 1) * 2 > CurQuestion->StorageWidth) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated value of STRING exceed its Size.\n");
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ } else {
+ if (memcmp((CHAR8 *)CurUqiList->Header.Value, ValueAddrOfVar, CurQuestion->StorageWidth) != 0) {
+ memcpy(
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy(
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ //
+ // Check and set the NUMERIC value
+ //
+ if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
+ if ((UqiValue < CurQuestion->Minimum) || (UqiValue > CurQuestion->Maximum)) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated value of NUMERIC 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ } else {
+ if (QuestionValue != UqiValue) {
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy (
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ }
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ //
+ // Check and set the ONE_OF value
+ //
+ if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
+ if (CheckOneOfParamError (CurQuestion, UqiValue)) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated ONE_OF value 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ } else {
+ if (QuestionValue != UqiValue) {
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy (
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ }
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ //
+ // Check and set the ORDER_LIST value
+ //
+ if (CurQuestion->Operand == EFI_IFR_ORDERED_LIST_OP) {
+ //
+ // Synchronize the MaxContainers value
+ //
+ *CurUqiList->Header.DiffValue = (UINT8)CurQuestion->MaxContainers;
+
+ if (CheckOrderParamError (CurQuestion, (CHAR8 *)CurUqiList->Header.Value)) {
+
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+
+ ErrorStr = CurUqiList->Error;
+ sprintf (ErrorStr, "Error. The updated NORDERED_LIST value ");
+ ErrorStr = ErrorStr + strlen ("Error. The updated NORDERED_LIST value ");
+
+ for (Index = 0; Index < CurQuestion->StorageWidth; Index++) {
+ sprintf (ErrorStr, "%02x ", *(CurUqiList->Header.Value + Index + 1));
+ ErrorStr +=3;
+ }
+ sprintf (ErrorStr, "is invalid.\n");
+ memcpy (
+ CurUqiList->Header.DiffValue + 1,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ } else {
+ for (Index = 0; Index < CurQuestion->StorageWidth/CurQuestion->MaxContainers; Index++) {
+ CurValue = 0;
+ memcpy (
+ &CurValue,
+ (ValueAddrOfVar + Index * CurQuestion->StorageWidth/CurQuestion->MaxContainers),
+ CurQuestion->StorageWidth/CurQuestion->MaxContainers
+ );
+ if (CurValue != *((UINT64 *)CurUqiList->Header.Value + Index + 1)) {
+ CurUqiList->SameOrNot = FALSE;
+ break;
+ }
+ }
+ if (!CurUqiList->SameOrNot) {
+ memcpy (
+ CurUqiList->Header.DiffValue + 1,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ for (Index = 0; Index < CurQuestion->MaxContainers; Index++) {
+ switch (CurQuestion->StorageWidth/CurQuestion->MaxContainers) {
+
+ case sizeof (UINT8):
+ *((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ case sizeof (UINT16):
+ *((UINT16 *)ValueAddrOfVar + Index) = *(UINT16 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ case sizeof (UINT32):
+ *((UINT32 *)ValueAddrOfVar + Index) = *(UINT32 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ case sizeof (UINT64):
+ *((UINT64 *)ValueAddrOfVar + Index) = *((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ default:
+ *((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+ }
+ }
+ //
+ // Update the vaule of ORDERED_LIST according to its size
+ //
+ CurUqiList->Header.Value = (UINT8 *)((UINT64 *)CurUqiList->Header.Value);
+ memcpy (
+ CurUqiList->Header.Value + 1,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse and set the quick configure information by the command line.
+
+ Read the UQI Config information from command line directly, and then compare it with the value in VarList.
+ Update the Update flag in Varlist.
+
+ @param UqiList The pointer to the uqi list
+ @param DefaultId The default Id.
+ @param PlatformId The platform Id.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @retval EFI_UNSUPPORTED Update a read-only value
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+SetUqiParameters (
+ IN UQI_PARAM_LIST *UqiList,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ FORM_BROWSER_FORM *Form;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ LIST_ENTRY *FormSetEntryListHead;
+ UQI_PARAM_LIST *CurUqiList;
+
+ FormSet = NULL;
+ FormSetLink = NULL;
+ Form = NULL;
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ FormSetEntryListHead = &mFormSetListEntry;
+
+ FormSetLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ // Parse all forms in formset
+ //
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ continue;
+ }
+ if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ continue;
+ }
+ }
+
+ CurUqiList = UqiList;
+ while (CurUqiList != NULL) {
+ if ((PlatformId == CurUqiList->Header.PlatformId[0])
+ && (DefaultId == CurUqiList->Header.DefaultId[0])
+ && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
+ ) {
+ //
+ // Add further check to avoid a case that there are many options with a
+ // same UQI (en-Us), but always returns the first one.
+ //
+ if (!CurUqiList->ParseOrNot) {
+ CurUqiList->ParseOrNot = TRUE;
+ break;
+ }
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+ if (CurUqiList != NULL) {
+ SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, Question);
+ }
+ }
+ }
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set question value per UqiList.
+
+ @param UqiList The pointer to the uqi list
+ @param DefaultId The default Id.
+ @param PlatformId The platform Id.
+**/
+VOID
+SetUqiParametersMultiMode (
+ IN UQI_PARAM_LIST *UqiList,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ UQI_PARAM_LIST *CurUqiList;
+
+ CurUqiList = UqiList;
+ while (CurUqiList != NULL) {
+ if ((CurUqiList->ParseOrNot == FALSE)
+ && (PlatformId == CurUqiList->Header.PlatformId[0])
+ && (DefaultId == CurUqiList->Header.DefaultId[0])
+ ) {
+ CurUqiList->ParseOrNot = TRUE;
+ if (CurUqiList->Header.Question != NULL) {
+ SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, CurUqiList->Header.Question);
+ }
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+}
+
+/**
+ Find the matched question for each UQI string in UqiList
+
+**/
+EFI_STATUS
+ScanUqiFullList (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ FORM_BROWSER_FORM *Form;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ LIST_ENTRY *FormSetEntryListHead;
+ UQI_PARAM_LIST *CurUqiList;
+ UINT64 PlatformId;
+ UINT16 DefaultId;
+
+ if (UqiList == NULL) {
+ return EFI_SUCCESS;
+ }
+ FormSet = NULL;
+ FormSetLink = NULL;
+ Form = NULL;
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ FormSetEntryListHead = &mFormSetListEntry;
+
+ FormSetLink = FormSetEntryListHead->ForwardLink;
+ while (FormSetEntryListHead != FormSetLink) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ // Parse all forms in formset
+ //
+ FormLink = FormSet->FormListHead.ForwardLink;
+
+ while (&FormSet->FormListHead != FormLink) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = Form->StatementListHead.ForwardLink;
+
+ while (&Form->StatementListHead != QuestionLink) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ QuestionLink = QuestionLink->ForwardLink;
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ continue;
+ } else if (Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ continue;
+ }
+
+ CurUqiList = UqiList;
+ PlatformId = 0xFFFFFFFF;
+ DefaultId = 0xFFFF;
+ while (CurUqiList != NULL) {
+ if ((CurUqiList->Header.Question == NULL)
+ && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
+ && ((PlatformId != CurUqiList->Header.PlatformId[0]) || (DefaultId != CurUqiList->Header.DefaultId[0]))
+ ) {
+ CurUqiList->Header.Question = Question;
+ PlatformId = CurUqiList->Header.PlatformId[0];
+ DefaultId = CurUqiList->Header.DefaultId[0];
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+ }
+ }
+ FormLink = FormLink->ForwardLink;
+ }
+ FormSetLink = FormSetLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create and insert the UQI Node to the UQI parameter list.
+
+ @retval Node address If successed, return the node address.
+ @retval NULL An error occurred.
+
+**/
+static
+UQI_PARAM_LIST *
+CreateInsertUqiNode (
+ )
+{
+ UQI_PARAM_LIST *Node;
+
+ Node = (UQI_PARAM_LIST *) malloc (sizeof (UQI_PARAM_LIST));
+ if (Node == NULL) {
+ return NULL;
+ }
+ memset (Node, 0, sizeof (UQI_PARAM_LIST));
+
+ if (mUqiList == NULL) {
+ mUqiList = Node;
+ } else {
+ mLastUqiList->Next = Node;
+ }
+
+ mLastUqiList = Node;
+ return Node;
+}
+/**
+ Parse the first part of QUI string
+
+ @param **argv[] The dual array pointer to the parameters.
+ @param Number The pointer to the number of the first character of UQI.
+ @param Buffer The buffer to store the first part of UQI.
+
+ @retval EFI_SUCCESS Parse the QUI parameters successfully.
+ @retval EFI_INVALID_PARAMETER An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseFirstpartOfUqi (
+ IN CHAR8 **argv[],
+ OUT UINT32 *Number,
+ OUT UINT16 **Buffer
+ )
+{
+ UINT32 Index;
+
+ Index = 0;
+
+ *Number = (UINT32)StrToDec ((*argv)[0]);
+
+ if ((*Number <= 0) || (*Number > MAX_QUI_PARAM_LEN)) {
+ printf ("Error. Invalid UQI.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Buffer = malloc ((*Number + 1) * sizeof (CHAR16));
+ assert (*Buffer != NULL);
+ memset (*Buffer, 0, (*Number + 1) * sizeof (CHAR16));
+
+ for (Index = 0; Index < *Number; Index++) {
+ if (StrToDec ((*argv)[Index]) > 0xff) {
+ printf ("Error. Invalid UQI.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ *(*Buffer + Index) = (UINT16)StrToDec ((*argv)[Index + 1]);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse the QUI input parameters from the command line
+
+ @param argc The pointer to the number of input parameters.
+ @param **argv[] The dual array pointer to the parameters.
+
+ @retval EFI_SUCCESS Parse the QUI parameters successfully.
+ @retval EFI_INVALID_PARAMETER An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseUqiParam (
+ IN UINT32 *argc,
+ IN CHAR8 **argv[]
+ )
+{
+ UINT32 Index;
+ UQI_PARAM_LIST *UqiNode;
+ EFI_STATUS Status;
+
+ Index = 0;
+ UqiNode = NULL;
+
+ if (*argc < 4) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UqiNode = CreateInsertUqiNode ();
+ assert (UqiNode != NULL);
+
+ UqiNode->Header.DefaultId = (UINT16 *) calloc (1, sizeof (UINT16));
+ UqiNode->Header.PlatformId = (UINT64 *) calloc (1, sizeof (UINT64));
+
+ Status = ParseFirstpartOfUqi (argv, &(UqiNode->Header.HexNum), &(UqiNode->Header.Data));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *argc -= (UqiNode->Header.HexNum + 1);
+ *argv += UqiNode->Header.HexNum + 1;
+ //
+ // Parse the TYPE and value
+ //
+ if (strcmp ("ONE_OF", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = ONE_OF;
+ } else if (strcmp ("NUMERIC", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = NUMERIC;
+ } else if (strcmp ("CHECKBOX", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = CHECKBOX;
+ } else if (strcmp ("STRING", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = STRING;
+ } else if (strcmp ("ORDERED_LIST", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = ORDERED_LIST;
+ } else {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ *argc -= 1;
+ *argv += 1;
+ //
+ // Get the value according to the type of questions.
+ //
+ switch (UqiNode->Header.Type) {
+
+ case ONE_OF:
+ case NUMERIC:
+ case CHECKBOX:
+ UqiNode->Header.Value = malloc (sizeof (UINT64));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (UqiNode->Header.Value, 0, sizeof (UINT64));
+
+ UqiNode->Header.DiffValue = malloc (sizeof (UINT64));
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ UqiNode->Header.DiffValue,
+ 0,
+ sizeof (UINT64)
+ );
+ *(UINT64 *)(UqiNode->Header.Value) = (UINT64)StrToDec ((*argv)[0]);
+ break;
+
+ case ORDERED_LIST:
+ UqiNode->Header.Value = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ UqiNode->Header.Value,
+ 0,
+ (UINTN)StrToDec(((*argv)[0]) + 1) * sizeof (UINT64)
+ );
+
+ UqiNode->Header.DiffValue = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ UqiNode->Header.DiffValue,
+ 0,
+ (UINTN)(StrToDec ((*argv)[0]) + 1) * sizeof (UINT64)
+ );
+
+ *UqiNode->Header.Value = (UINT8)StrToDec ((*argv)[0]);
+ for (Index = 1; Index <= StrToDec ((*argv)[0]); Index++) {
+ *((UINT64 *)UqiNode->Header.Value + Index) = StrToDec ((*argv)[Index]);
+ }
+ *argc -= (UINTN)StrToDec ((*argv)[0]);
+ *argv += (UINTN)StrToDec ((*argv)[0]);
+ break;
+
+ default:
+ break;
+ }
+
+ *argc -= 1;
+ *argv += 1;
+
+ if (*argc > 0) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Parse the input Fd file, and get the file name according to the FILETYPE.
+
+ @param FdName The Name of Fd file
+ @param FILETYPE The type of Fd file
+
+ @return EFI_SUCCESS Get the file name successfully
+ @return EFI_ABORTED An error occurred.
+**/
+static
+EFI_STATUS
+ParseInFile (
+ IN CHAR8 *FdName,
+ IN FILETYPE Type
+)
+{
+ FILE *Fptr;
+
+ Fptr = NULL;
+
+ if ((Type == INFD) && ((FdName == NULL) || (Fptr = fopen (FdName, "r")) == NULL)) {
+ if (FdName != NULL) {
+ printf ("Error: The <infd> file doesn't exist '%s'\n", FdName);
+ }
+ return EFI_ABORTED;
+ }
+ if ((Type == OUTFD) && (FdName == NULL) ) {
+ printf ("Error: The <Outfd> name is NULL.\n");
+ return EFI_ABORTED;
+ }
+ if ((Type == SETUPTXT) && (FdName == NULL) ) {
+ printf ("Error: The <script> name is NULL.\n");
+ return EFI_ABORTED;
+ }
+ if (strlen (FdName) > MAX_FILENAME_LEN - 1) {
+ printf ("Error: The <fd> name is too long.\n");
+ if (Fptr != NULL) {
+ fclose (Fptr);
+ }
+ return EFI_ABORTED;
+ }
+ //
+ // Get and copy the file name
+ //
+ if (Type == INFD) {
+ strncpy (mInputFdName, FdName, MAX_FILENAME_LEN - 1);
+ mInputFdName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Type == OUTFD) {
+ strncpy (mOutputFdName, FdName, MAX_FILENAME_LEN - 1);
+ mOutputFdName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Type == OUTTXT) {
+ strncpy (mOutTxtName, FdName, MAX_FILENAME_LEN - 1);
+ mOutTxtName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Type == SETUPTXT) {
+ strncpy (mSetupTxtName, FdName, MAX_FILENAME_LEN - 1);
+ mSetupTxtName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Fptr != NULL) {
+ fclose (Fptr);
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Print the usage of this tools.
+
+ @return NULL
+**/
+static
+VOID
+Usage (
+ VOID
+ )
+{
+ //
+ // Print utility header
+ //
+ printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
+ UTILITY_NAME,
+ UTILITY_MAJOR_VERSION,
+ UTILITY_MINOR_VERSION,
+ __BUILD_VERSION
+ );
+ //
+ // Copyright declaration
+ //
+ fprintf (stdout, "Copyright (c) 2010-2018, Intel Corporation. All rights reserved.\n\n");
+ //
+ // Summary usage
+ //
+ fprintf (stdout, "The tool enables you to retrieve and change HII configuration (Setup) data in \n");
+ fprintf (stdout, "Firmware Device files.\n");
+ fprintf (stdout, "\nUsage: \n");
+ fprintf (stdout, " FCE [read -i <infd> [<PlatformId UQI>] ['>' <script>]] \n");
+ fprintf (stdout, " FCE [update -i <infd> [<PlatformId UQI>|-s <script>] -o <outfd>\n");
+ fprintf (stdout, " [--remove|--ignore] [-g <FvNameGuid>]] [-a]\n");
+ fprintf (stdout, " FCE [verify -i <infd> -s <script>] \n");
+ fprintf (stdout, " FCE [updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>] \n");
+ fprintf (stdout, " FCE [[help] | [-?]] \n");
+ fprintf (stdout, "\n");
+
+ fprintf (stdout, "Options:\n");
+ fprintf (stdout, " read Extract the HII data from the <infd> file. \n");
+ fprintf (stdout, " update Update the HII data to the <outfd> file. \n");
+ fprintf (stdout, " verify Verify the current platform configuration. \n");
+ fprintf (stdout, " updateq Update the current platform configuration by command line.\n");
+ fprintf (stdout, " updateq only supports common mode.\n");
+ fprintf (stdout, " help Display the help information.\n");
+
+ fprintf (stdout, " <infd> The name of a existing Firmware Device binary file input. \n");
+ fprintf (stdout, " <PlatformId UQI> The UQI is required in multi-platform mode to represent a \n");
+ fprintf (stdout, " PlatformId question from the VFR files used during binary \n");
+ fprintf (stdout, " image creation. It must not be used for common mode. \n");
+ fprintf (stdout, " <outfd> The name of a Firmware Device binary file output. \n");
+ fprintf (stdout, " <script> The name of a configure scripts.\n");
+ fprintf (stdout, " <UQI> A hex number followed by an array of hex numbers. \n");
+ fprintf (stdout, " <Question Type> One of ORDERED_LIST, ONE_OF, NUMERIC, STRING or CHECKBOX. \n");
+ fprintf (stdout, " <Value> A single hex number, if the <Question Type> is ONE_OF,\n");
+ fprintf (stdout, " NUMERIC, or CHECKBOX. Or a single hex number containing \n");
+ fprintf (stdout, " the array size followed by an array of that length of hex\n");
+ fprintf (stdout, " numbers, if the <Question Type> is ORDERED_LIST. \n");
+ fprintf (stdout, " <FvNameGuid> GuidValue is one specific FvName guid value.\n");
+ fprintf (stdout, " Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.\n");
+ fprintf (stdout, " -i Import an existing FD file <infd>. \n");
+ fprintf (stdout, " -o Create the new FD with the changes made. \n");
+ fprintf (stdout, " -s Import config scripts. \n");
+ fprintf (stdout, " > Redirect the output to a scripts. \n");
+ fprintf (stdout, " -? Display the help information. \n");
+ fprintf (stdout, " --remove If one or more of the settings that are updated also \n");
+ fprintf (stdout, " exists in NV RAM, remove them only in multi-platform mode.\n");
+ fprintf (stdout, " --ignore If one or more of the settings that are updated also \n");
+ fprintf (stdout, " existsin NV RAM, ignore them only in multi-platform mode.\n");
+ fprintf (stdout, " -g Specify the FV image to store the multi-platform default \n");
+ fprintf (stdout, " setting. If it is missing, the multi-platform default \n");
+ fprintf (stdout, " will be inserted into BFV image.\n");
+ fprintf (stdout, " -a Specify this tool to choose the smaller size between two \n");
+ fprintf (stdout, " different storage formats in NV RAM. It's only vaild in \n");
+ fprintf (stdout, " multi-platform mode. \n");
+ fprintf (stdout, "\n");
+
+ fprintf (stdout, "Mode:\n");
+ fprintf (stdout, " Common Extract the HII data from IFR binary and update it to the \n");
+ fprintf (stdout, " EFI variable. \n");
+ fprintf (stdout, " Multi-platform The default value depends on the PlatformId and DefaultId \n");
+ fprintf (stdout, " described in the VFR files. This tool will create the \n");
+ fprintf (stdout, " binary file to store default settings at build time for \n");
+ fprintf (stdout, " different platforms and modes adding all default settings \n");
+ fprintf (stdout, " into BFV as one FFS.\n");
+
+ fprintf (stdout, "\n");
+}
+
+/**
+ Parse the command line parameters
+
+ @param argc The pointer to number of input parameters.
+ @param *argv[] The pointer to the parameters.
+
+ @retval EFI_SUCCESS Parse the parameters successfully.
+ @retval EFI_INVALID_PARAMETER An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseCommmadLine (
+ IN UINTN argc,
+ IN CHAR8 *argv[]
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT8 IndexParamI;
+ UINT8 IndexParamS;
+ UINT8 IndexParamO;
+ UINT8 IndexParamRemove;
+ UINT8 IndexParamIgnore;
+ UINT8 IndexParamOptimize;
+ EFI_GUID FvNameGuid;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+ IndexParamI = 0;
+ IndexParamO = 0;
+ IndexParamS = 0;
+ IndexParamRemove = 0;
+ IndexParamIgnore = 0;
+ IndexParamOptimize = 0;
+ mMultiPlatformParam.SizeOptimizedParam = FALSE;
+ //
+ // Check for only own one operations
+ //
+ if (argc == 0) {
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ if (
+ argc == 1 \
+ && ((stricmp(argv[0], "read") == 0) \
+ || (stricmp(argv[0], "update") == 0) \
+ || (stricmp(argv[0], "updateq") == 0) \
+ || (stricmp(argv[0], "verify") == 0) )
+ ) {
+ printf ("Error: Some parameters have been lost. Please correct. \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ while (argc > 0) {
+ if (stricmp(argv[0], "read") == 0) {
+ Operations = READ;
+ argc--;
+ argv++;
+
+ if (argc < 2) {
+ printf ("Error. The correct command is 'FCE read -i <infd>'. \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Get input FD file name.
+ //
+ if (stricmp (argv[0], "-i") == 0) {
+ Status = ParseInFile (argv[1], INFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ }
+ //
+ // Parse the QUI parameters
+ //
+ if (argc > 2) {
+ Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ break;
+
+ } else if (stricmp(argv[0], "update") == 0) {
+ //
+ // Update the config file to Fd
+ //
+ Operations = UPDATE;
+ argc--;
+ argv++;
+
+ if (argc < 4) {
+ printf ("Error. The correct command is 'FCE update -i <infd> [<PlatformId UQI>|-s <script>] -o <outfd>' \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ continue;
+ } else if (stricmp(argv[0], "verify") == 0) {
+ //
+ // 3. Parse the command line "FCE verify -i <infd> -s <script>"
+ //
+ Operations = VERIFY;
+ argc--;
+ argv++;
+
+ if (argc < 4) {
+ printf ("Error. The correct command is 'FCE verify -i <infd> -s <script>'\n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ continue;
+ } else if (stricmp(argv[0], "updateq") == 0) {
+ //
+ // Parse the command line "FCE updateq -i <infd> -o<outfd> <UQI> <Question Type> <Value>"
+ //
+ argc--;
+ argv++;
+
+ //
+ // Get input/output FD file name.
+ //
+ Index = 2;
+ while ((Index > 0) && (argc > 1)) {
+ if (stricmp (argv[0], "-i") == 0) {
+ Status = ParseInFile (argv[1], INFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ Index--;
+ IndexParamI++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-o") == 0) {
+ Status = ParseInFile (argv[1], OUTFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ Index--;
+ IndexParamO++;
+ continue;
+ }
+ if (
+ (argc >= 1) \
+ && (stricmp(argv[0], "-o") != 0) \
+ && (stricmp(argv[0], "-i") != 0)
+ ) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ if (Index != 0) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Parse the QUI parameters
+ //
+ Status = ParseUqiParam ((UINT32 *)&argc,&argv);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Operations = UPDATEQ;
+ break;
+ }
+
+ if (stricmp (argv[0], "-i") == 0) {
+ Status = ParseInFile (argv[1], INFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ IndexParamI++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-o") == 0) {
+ Status = ParseInFile (argv[1], OUTFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ IndexParamO++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-s") == 0) {
+ Status = ParseInFile (argv[1], SETUPTXT);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ IndexParamS++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-g") == 0) {
+ Status = StringToGuid (argv[1], &FvNameGuid);
+ if (EFI_ERROR (Status)) {
+ printf ("Error: Invalid parameters for -g option in command line. \n");
+ Usage();
+ goto Done;
+ }
+ mFvNameGuidString = argv[1];
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-a") == 0) {
+ argc -= 1;
+ argv += 1;
+ IndexParamOptimize++;
+ mMultiPlatformParam.SizeOptimizedParam = TRUE;
+ continue;
+ }
+
+ if (stricmp (argv[0], "--remove") == 0) {
+ argc -= 1;
+ argv += 1;
+ IndexParamRemove++;
+ Operations = UPDATE_REMOVE;
+ continue;
+ }
+
+ if (stricmp (argv[0], "--ignore") == 0) {
+ argc -= 1;
+ argv += 1;
+ IndexParamIgnore++;
+ Operations = UPDATE_IGNORE;
+ continue;
+ }
+
+ if ((stricmp(argv[0], "help") == 0) || (stricmp(argv[0], "-?") == 0)) {
+
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Operations should not be none
+ //
+ if ( Operations == NONE ) {
+ printf ("Error. Only support read/update/verify/updateq mode. \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Operations == UPDATE) {
+ Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
+ if (!EFI_ERROR (Status)) {
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ argc = argc - mMultiPlatformParam.Uqi.HexNum - 1;
+ argv = argv + mMultiPlatformParam.Uqi.HexNum + 1;
+ continue;
+ }
+ }
+
+ if (
+ (argc >= 1) \
+ && (stricmp(argv[0], "-?") != 0)
+ && (stricmp(argv[0], "help") != 0)
+ && (stricmp(argv[0], "verify") != 0)
+ && (stricmp(argv[0], "read") != 0)
+ && (stricmp(argv[0], "update") != 0)
+ && (stricmp(argv[0], "updateq") != 0)
+ && (stricmp(argv[0], "-o") != 0)
+ && (stricmp(argv[0], "-i") != 0)
+ && (stricmp(argv[0], "-s") != 0)
+ && (stricmp(argv[0], "-a") != 0)
+ && (stricmp(argv[0], "-g") != 0)
+ && (stricmp(argv[0], "--remove") != 0)
+ && (stricmp(argv[0], "--ignore") != 0)
+ ) {
+ printf ("Error: Invalid parameters exist in command line. \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ //
+ // Check the repeated parameters in command line, such as "-i -i"
+ //
+ if (
+ (IndexParamI > 1)
+ || (IndexParamO > 1)
+ || (IndexParamS > 1)
+ || (IndexParamOptimize > 1)
+ || (IndexParamRemove > 1)
+ || (IndexParamIgnore > 1)
+ ) {
+ printf ("Error: Redundant parameters exist in command line.\n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check improper parameters in command line, such as "FCE read -i -s"
+ //
+ if (
+ ((Operations == READ) && ((IndexParamO >= 1) || (IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+ || ((Operations == VERIFY) && ((IndexParamO >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+ || ((Operations == UPDATEQ) && ((IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+ || ((Operations == UPDATE) && ((IndexParamRemove >= 1) && (IndexParamIgnore >= 1)))
+ || ((Operations != UPDATE && Operations != UPDATE_REMOVE && Operations != UPDATE_IGNORE) && ((IndexParamOptimize >= 1) || (mFvNameGuidString != NULL)))
+ ) {
+ printf ("Error: Improper parameters exist in command line. \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+Done:
+ return Status;
+}
+
+/**
+ Check whether exists the valid variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+static
+BOOLEAN
+ExistEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ BOOLEAN Existed;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ Existed = TRUE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Check the Monotonic based authenticate variable
+ //
+ Existed = ExistMonotonicBasedEfiVarOrNot (StorageListHead);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Check the Time Sample authenticate variable
+ //
+ Existed = ExistTimeBasedEfiVarOrNot (StorageListHead);
+ } else {
+ //
+ // Check the normal variable
+ //
+ Existed = ExistNormalEfiVarOrNot (StorageListHead);
+ }
+
+ return Existed;
+}
+
+/**
+ Exchange the data between Efi variable and the data of VarList
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+static
+EFI_STATUS
+EfiVarAndListExchange (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ EFI_STATUS Status;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ Status = EFI_ABORTED;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Update the Monotonic based authenticate variable
+ //
+ Status = SynAuthEfiVariable (VarToList, StorageListHead);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Update the Time Sample authenticate variable
+ //
+ Status = SynAuthEfiVariableBasedTime (VarToList, StorageListHead);
+ } else {
+ //
+ // Update the normal variable
+ //
+ Status = SynEfiVariable (VarToList, StorageListHead);
+ }
+
+ return Status;
+}
+
+/**
+ Check the layout of NvStorage and remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+static
+EFI_STATUS
+RemoveEfiVar (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ EFI_STATUS Status;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ Status = EFI_ABORTED;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Update the Monotonic based authenticate variable
+ //
+ Status = RemoveAuthEfiVariable (StorageListHead);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Update the Time Sample authenticate variable
+ //
+ Status = RemoveAuthEfiVariableBasedTime (StorageListHead);
+ } else {
+ //
+ // Update the normal variable
+ //
+ Status = RemoveNormalEfiVariable (StorageListHead);
+ }
+
+ return Status;
+}
+
+/**
+ Parse the all formset in one VfrBin.
+
+ Parse all questions, variables and expression in VfrBin, and store
+ it in Formset and Form.
+
+ @param BaseAddr The pointer to the array of VfrBin base address.
+ @param UniBinBaseAddress The pointer to one Uni string base address.
+
+ @retval EFI_SUCCESS The Search was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ParseFormSetInVfrBin (
+ IN UINTN **BaseAddr,
+ IN UINTN *UniBinBaseAddress,
+ IN UINT8 Index
+ )
+{
+ UINT32 PackageLength;
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *FormSet;
+ UINT8 *IfrBinaryData;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ UINT32 IfrOffset;
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+ FormSet = NULL;
+ IfrBinaryData = NULL;
+ IfrOpHdr = NULL;
+
+ //
+ // The first 4 Bytes of VfrBin is used to record the Array Length
+ // The header of VfrBin is, ARRAY LENGTH:4 Bytes, PACKAGE HEADER:4 Bytes (2 Bytes for Len, and the other for Type)
+ //
+ PackageLength = *(UINT32 *)*(BaseAddr + Index) - 4;
+ IfrBinaryData = (UINT8 *)*(BaseAddr + Index) + 4;
+
+ //
+ // Go through the form package to parse OpCode one by one.
+ //
+ IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+
+ while (IfrOffset < PackageLength) {
+ //
+ // Search the Formset in VfrBin
+ //
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) (IfrBinaryData + IfrOffset);
+
+ if (IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) {
+ FormSet = calloc (sizeof (FORM_BROWSER_FORMSET), sizeof (CHAR8));
+ if (FormSet == NULL) {
+ return EFI_ABORTED;
+ }
+ FormSet->IfrBinaryData = IfrBinaryData + IfrOffset;
+ FormSet->UnicodeBinary = (UINT8 *) UniBinBaseAddress;
+ //
+ //This length will be corrected in ParseOpCodes function.
+ //
+ FormSet->IfrBinaryLength = PackageLength - IfrOffset;
+ //
+ // Parse opcodes in the formset IFR binary.
+ //
+ Status = ParseOpCodes (FormSet);
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (FormSet->StorageListHead);
+ DestroyFormSet (FormSet);
+ return EFI_ABORTED;
+ }
+ IfrOffset += FormSet->IfrBinaryLength;
+ FormSet->EnUsStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
+ FormSet->EnUsStringList.CachedIdNum = 0;
+ FormSet->EnUsStringList.MaxIdNum = STRING_NUMBER;
+ FormSet->UqiStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
+ FormSet->UqiStringList.CachedIdNum = 0;
+ FormSet->UqiStringList.MaxIdNum = STRING_NUMBER;
+ //
+ // Insert the FormSet to mFormSet
+ //
+ InsertTailList (&mFormSetListEntry, &FormSet->Link);
+ } else {
+ IfrOffset += IfrOpHdr->Length;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Store all defaultId to mMultiPlatformParam.
+
+ The mMultiPlatformParam.DefaultId[0] is used to store standard default.
+
+ @param DefaultId The current defaultID.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+VOID
+StoreAllDefaultId (
+ IN UINT16 DefaultId
+)
+{
+ UINT32 Index;
+
+ if ((mMultiPlatformParam.DefaultIdNum == 0) && (DefaultId != 0)) {
+ mMultiPlatformParam.DefaultId[0] = DefaultId;
+ mMultiPlatformParam.DefaultIdNum++;
+ return;
+ }
+ //
+ // Only store the different value to mMultiPlatformParam.DefaultId[1] - mMultiPlatformParam.DefaultId[n]
+ //
+ for (Index = 0; Index < mMultiPlatformParam.DefaultIdNum; Index++) {
+ if (mMultiPlatformParam.DefaultId[Index] == DefaultId) {
+ return;
+ }
+ }
+ mMultiPlatformParam.DefaultId[Index] = DefaultId;
+ mMultiPlatformParam.DefaultIdNum++;
+}
+
+/**
+ Read all defaultId and platformId from binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+**/
+VOID
+ReadDefaultAndPlatformIdFromBfv (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+)
+{
+ UINT16 Length;
+ UINT16 Size;
+ UINT32 Index;
+
+ Length = *(UINT16 *)Binary - sizeof (UINT16);
+ Index = 0;
+ Size = 0;
+
+ Binary = Binary + sizeof (UINT16);
+
+ for (Size = 0; Size < Length; Size += sizeof (UINT16) + mMultiPlatformParam.PlatformIdWidth, Index++) {
+ Storage->DefaultId[Index] = *(UINT16 *)(Binary + Size);
+ memcpy (&Storage->PlatformId[Index], (Binary + Size + sizeof (UINT16)), mMultiPlatformParam.PlatformIdWidth);
+ }
+ Storage->DefaultPlatformIdNum = Index - 1;
+}
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+UINT32
+WriteDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+)
+{
+ UINT16 Length;
+ UINT32 Index;
+ UINT8 *Buffer;
+
+ Length = 0;
+ Buffer = Binary;
+
+ Buffer = Buffer + sizeof (CHAR16);
+
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ *(UINT16 *)Buffer = Storage->DefaultId[Index];
+ Buffer = Buffer + sizeof (CHAR16);
+ memcpy (Buffer, &Storage->PlatformId[Index], mMultiPlatformParam.PlatformIdWidth);
+ Buffer = Buffer + mMultiPlatformParam.PlatformIdWidth;
+ }
+ Length = (UINT16) (Buffer - Binary);
+ //
+ // Record the offset to the first two bytes
+ //
+ *(UINT16 *)Binary = Length;
+
+ return Length;
+}
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+UINT32
+WriteNvStoreDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+)
+{
+ UINT16 Length;
+ UINT32 Index;
+ UINT8 *Buffer;
+
+ Length = 0;
+ Buffer = Binary + 8;
+
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ *(UINT64 *)Buffer = Storage->PlatformId[Index];
+ Buffer = Buffer + sizeof(UINT64);
+ *(UINT16 *)Buffer = Storage->DefaultId[Index];
+ Buffer = Buffer + sizeof(UINT16);
+ // for Resered
+ Buffer = Buffer + 6;
+ }
+ Length = (UINT16) (Buffer - Binary - 8);
+ // for Header size
+ Length += 4;
+ return Length;
+}
+
+/**
+ Read the platformId from questions.
+
+ @retval EFI_SUCCESS It was complete successfully.
+ @return EFI_ABORTED An error occurred.
+**/
+EFI_STATUS
+ReadPlaformId (
+ IN FORM_BROWSER_STATEMENT *CurQuestion
+)
+{
+ UINT16 Index;
+ UINT64 IdValue;
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ UINT64 Step;
+
+ Index = 0;
+ IdValue = 0;
+ Step = 0;
+ //
+ // Check whether it is the question of paltform Id
+ //
+ if (!CompareUqiHeader (&(CurQuestion->Uqi), &(mMultiPlatformParam.Uqi))) {
+ return EFI_ABORTED;
+ }
+ //
+ // Copy the Question with platform to mMultiPlatformParam
+ //
+ memcpy (&mMultiPlatformParam.PlatformIdQuestion, CurQuestion, sizeof (FORM_BROWSER_STATEMENT));
+ mMultiPlatformParam.Question = CurQuestion;
+ //
+ // Pick up the value of NUMERIC and ONE_OF from current question and fill it in mMultiPlatformParam
+ //
+ mMultiPlatformParam.PlatformIdWidth = CurQuestion->StorageWidth;
+
+ if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
+ Index = 0;
+ if (CurQuestion->Step == 0) {
+ Step = 1;
+ } else {
+ Step = CurQuestion->Step;
+ }
+ for (IdValue = CurQuestion->Minimum; IdValue < CurQuestion->Maximum; IdValue += Step) {
+ mMultiPlatformParam.PlatformId[Index++] = (UINT64)IdValue;
+ }
+ }
+
+ if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
+ Index = 0;
+
+ Link = GetFirstNode (&CurQuestion->OptionListHead);
+ while (!IsNull (&CurQuestion->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ mMultiPlatformParam.PlatformId[Index++] = Option->Value.Value.u64;
+ Link = GetNextNode (&CurQuestion->OptionListHead, Link);
+ }
+ }
+
+ if (Index >= MAX_PLATFORM_DEFAULT_ID_NUM) {
+ return EFI_ABORTED;
+ }
+ mMultiPlatformParam.PlatformIdNum = Index;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clear the buffer of Storage list.
+
+ @param StorageListHead The pointer to the entry of the storage list
+ @param DefaultId The default Id for multi-platform support
+ @param PlatformId The platform Id for multi-platform support
+
+ @retval NULL
+**/
+VOID
+ClearStorageEntryList (
+ IN LIST_ENTRY *StorageListHead,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+
+ Storage = NULL;
+
+ StorageLink = GetFirstNode (StorageListHead);
+
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (Storage != NULL) {
+ memset (Storage->Buffer, 0x0, Storage->Size);
+ Storage->DefaultId[0] = DefaultId;
+ Storage->PlatformId[0] = PlatformId;
+ Storage->DefaultPlatformIdNum = 0;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+}
+
+/**
+ Append the platformid and default to the variables of CurDefaultId and CurPlatformId
+
+ @param StorageListHead The pointer to the storage list
+ @param CurDefaultId The default Id for multi-platform mode
+ @param CurPlatformId The platform Id for multi-platform mode
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+
+ @retval NULL
+**/
+VOID
+AppendIdToVariables (
+ IN LIST_ENTRY *StorageListHead,
+ IN UINT16 CurDefaultId,
+ IN UINT64 CurPlatformId,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+)
+{
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+
+ Storage = NULL;
+
+ StorageLink = GetFirstNode (StorageListHead);
+
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+
+ if ((Storage->DefaultId[0] == CurDefaultId)
+ && (Storage->PlatformId[0] == CurPlatformId)
+ ) {
+ ++Storage->DefaultPlatformIdNum;
+ Storage->DefaultId[Storage->DefaultPlatformIdNum] = DefaultId;
+ Storage->PlatformId[Storage->DefaultPlatformIdNum] = PlatformId;
+ }
+
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+}
+
+
+/**
+ Check whether StorageListHead2 is included in StorageListHead1
+
+ @param StorageListHead1 The pointer to the entry of storage list
+ @param StorageListHead2 The pointer to the entry of storage list
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+
+ @retval TRUE Totally included.
+ @return FALSE Other cases.
+**/
+BOOLEAN
+ComparePartSameVariableList (
+ IN LIST_ENTRY *StorageListHead1,
+ IN LIST_ENTRY *StorageListHead2,
+ OUT UINT16 *DefaultId,
+ OUT UINT64 *PlatformId
+)
+{
+ LIST_ENTRY *StorageLink;
+ LIST_ENTRY *TempStorageHead;
+ LIST_ENTRY *TempStorageLink;
+ LIST_ENTRY *TempStorageHead2;
+ LIST_ENTRY *TempStorageLink2;
+ FORMSET_STORAGE *Storage;
+ FORMSET_STORAGE *TempStorage;
+ FORMSET_STORAGE *TempStorage2;
+ UINT16 CurDefaultId;
+ UINT64 CurPlatformId;
+ UINT32 VariableNum;
+ UINT32 Index;
+
+ StorageLink = NULL;
+ TempStorageHead = NULL;
+ TempStorageLink = NULL;
+ TempStorageHead2 = NULL;
+ TempStorageLink2 = NULL;
+ Storage = NULL;
+ TempStorage = NULL;
+ TempStorage2 = NULL;
+ CurDefaultId = 0;
+ CurPlatformId = 0;
+ VariableNum = 0;
+ Index = 0;
+ TempStorageHead = StorageListHead1;
+
+
+ //
+ // Get the number of variables in StorageListHead2;
+ //
+ StorageLink = GetFirstNode (StorageListHead2);
+
+ while (!IsNull (StorageListHead2, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // For multi-platform support, only need to calcuate the type of EFI_IFR_VARSTORE_EFI_OP.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot &&
+ (Storage->Type == EFI_IFR_VARSTORE_EFI_OP) && (Storage->Name != NULL) && (Storage->NewEfiVarstore) &&
+ ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)) {
+ VariableNum++;
+ }
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ }
+ //
+ // Parse every variables in StorageListHead1 and compare with ones in StorageListHead2
+ // Only all variables in StorageListHead2 are included in StorageListHead1, return TRUE.
+ //
+ StorageLink = GetFirstNode (StorageListHead1);
+
+ while (!IsNull (StorageListHead1, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Get specified DefaultId and PlatformId firstly
+ //
+ CurDefaultId = Storage->DefaultId[0];
+ CurPlatformId = Storage->PlatformId[0];
+ Index = 0;
+ //
+ // Compare all variables under same defaultId and platformId
+ //
+ TempStorageLink = GetFirstNode (TempStorageHead);
+ while (!IsNull (TempStorageHead, TempStorageLink)) {
+ TempStorage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
+ if ((TempStorage->DefaultId[0] == CurDefaultId)
+ && (TempStorage->PlatformId[0] == CurPlatformId)
+ && (TempStorage->Name != NULL)
+ && (TempStorage->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && (TempStorage->NewEfiVarstore)
+ && ((TempStorage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
+ ) {
+ //
+ //Search the matched variable by Guid and name in StorageListHead2
+ //
+ TempStorageHead2 = StorageListHead2;
+ TempStorageLink2 = GetFirstNode (TempStorageHead2);
+
+ while (!IsNull (TempStorageHead2, TempStorageLink2)) {
+ TempStorage2 = FORMSET_STORAGE_FROM_LINK (TempStorageLink2);
+ if ((TempStorage2->Name != NULL)
+ && (TempStorage2->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && (TempStorage2->NewEfiVarstore)
+ && ((TempStorage2->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
+ && !FceStrCmp (TempStorage->Name, TempStorage2->Name)
+ && !CompareGuid(&TempStorage->Guid, &TempStorage2->Guid)
+ ) {
+ if (CompareMem (TempStorage->Buffer, TempStorage2->Buffer, TempStorage->Size) == 0) {
+ Index++;
+ }
+ }
+ TempStorageLink2 = GetNextNode (TempStorageHead2, TempStorageLink2);
+ }
+ }
+ TempStorageLink = GetNextNode (TempStorageHead, TempStorageLink);
+ }
+ //
+ // Check the matched variable number
+ //
+ if (Index == VariableNum) {
+ *DefaultId = CurDefaultId;
+ *PlatformId = CurPlatformId;
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead1, StorageLink);
+ }
+ return FALSE;
+}
+
+/**
+ Check whether the defaultId and platformId mathched the variable or not
+
+ @param Storage The pointer to the storage
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+
+ @retval TRUE Not Matched.
+ @return FALSE Matched any one
+**/
+BOOLEAN
+NotEqualAnyIdOfStorage (
+IN FORMSET_STORAGE *Storage,
+IN UINT16 DefaultId,
+IN UINT64 PlatformId
+)
+{
+ UINT32 Index;
+
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ if ((Storage->DefaultId[Index] == DefaultId)
+ &&(Storage->PlatformId[Index] == PlatformId)
+ ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Copy Stroage from StorageListHead2 to StorageListHead1
+
+ @param NewStorageListHead The pointer to the entry of storage list
+ @param OldStorageListHead The pointer to the entry of storage list
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+ @param AssignIdOrNot If True, assign the platform Id and default Id to storage;
+ Or else, only copy the variables under the specified platform
+ Id and default to the other list.
+ @param Mode The operation of mode
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+BuildVariableList (
+ IN LIST_ENTRY *NewStorageListHead,
+ IN LIST_ENTRY *OldStorageListHead,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN BOOLEAN AssignIdOrNot,
+ IN OPERATION_TYPE Mode
+)
+{
+ LIST_ENTRY *StorageLink;
+ LIST_ENTRY *NameValueLink;
+ FORMSET_STORAGE *Storage;
+ FORMSET_STORAGE *StorageCopy;
+ IN LIST_ENTRY *StorageListHead1;
+ IN LIST_ENTRY *StorageListHead2;
+ NAME_VALUE_NODE *NameValueNode;
+ NAME_VALUE_NODE *CopyNameValueNode;
+
+ Storage = NULL;
+ NameValueNode = NULL;
+ StorageListHead1 = NewStorageListHead;
+ StorageListHead2 = OldStorageListHead;
+
+ StorageLink = GetFirstNode (StorageListHead2);
+
+ while (!IsNull (StorageListHead2, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+
+ if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
+ ||(Storage->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ //
+ // Only support EfiVarStore in Multi-Platform mode, and the attribute must be EFI_VARIABLE_NON_VOLATILE
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (Storage->Type == EFI_IFR_VARSTORE_OP) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ }
+ if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ }
+ if (AssignIdOrNot) {
+ Storage->DefaultId[0] = DefaultId;
+ Storage->PlatformId[0] = PlatformId;
+ } else {
+ //
+ //only copy the variables under the specified platform Id and default to the other list.
+ //
+ if ((Mode == VERIFY) && (NotEqualAnyIdOfStorage (Storage, DefaultId, PlatformId))) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ } else if ((Mode != VERIFY) && (Storage->DefaultId[0] != DefaultId || Storage->PlatformId[0] != PlatformId) ) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ }
+ }
+ }
+ //
+ // Copy Storage Node
+ //
+ if (Storage->Name == NULL) {
+ return EFI_ABORTED;
+ }
+ StorageCopy = NULL;
+ StorageCopy = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (StorageCopy == NULL) {
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (StorageCopy, Storage, sizeof (FORMSET_STORAGE));
+
+ if (Mode == VERIFY) {
+ StorageCopy->DefaultId[0] = DefaultId;
+ StorageCopy->PlatformId[0] = PlatformId;
+ }
+ //
+ //Set the flags for sorting out the variables
+ //
+ StorageCopy->Skip = FALSE;
+
+ StorageCopy->Name = NULL;
+ StorageCopy->Name = calloc (FceStrLen (Storage->Name) + 1, sizeof (CHAR16));
+ if (StorageCopy->Name == NULL) {
+ printf ("Memory allocation failed.\n");
+ free (StorageCopy);
+ return EFI_ABORTED;
+ }
+ StrCpy (StorageCopy->Name, Storage->Name);
+
+ StorageCopy->Buffer = NULL;
+ StorageCopy->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ if (StorageCopy->Buffer == NULL) {
+ free (StorageCopy->Name);
+ free (StorageCopy);
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ CopyMem (StorageCopy->Buffer, Storage->Buffer, Storage->Size);
+ //
+ // Copy NameValue list of storage node
+ //
+ InitializeListHead (&StorageCopy->NameValueListHead);
+
+ NameValueLink = GetFirstNode (&Storage->NameValueListHead);
+
+ while (!IsNull (&Storage->NameValueListHead, NameValueLink)) {
+
+ NameValueNode = NAME_VALUE_NODE_FROM_LINK (NameValueLink);
+ CopyNameValueNode = NULL;
+ CopyNameValueNode = calloc (sizeof (NAME_VALUE_NODE), sizeof (CHAR8));
+ if (CopyNameValueNode == NULL) {
+ free (StorageCopy->Name);
+ free (StorageCopy->Buffer);
+ free (StorageCopy);
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (CopyNameValueNode, NameValueNode, sizeof (NAME_VALUE_NODE));
+
+ CopyNameValueNode->Name = NULL;
+ CopyNameValueNode->Value = NULL;
+ CopyNameValueNode->EditValue = NULL;
+
+ CopyNameValueNode->Name = calloc (FceStrLen (NameValueNode->Name) + 1, sizeof (CHAR16));
+ CopyNameValueNode->Value = calloc (FceStrLen (NameValueNode->Value) + 1, sizeof (CHAR16));
+ CopyNameValueNode->EditValue = calloc (FceStrLen (NameValueNode->EditValue) + 1, sizeof (CHAR16));
+ if ((CopyNameValueNode->Name == NULL)
+ || (CopyNameValueNode->Value == NULL)
+ || (CopyNameValueNode->EditValue == NULL)
+ ) {
+ free (StorageCopy->Name);
+ free (StorageCopy->Buffer);
+ free (StorageCopy);
+ if (CopyNameValueNode->Name != NULL) {
+ free (CopyNameValueNode->Name );
+ }
+ if (CopyNameValueNode->Value != NULL) {
+ free (CopyNameValueNode->Value);
+ }
+ if (CopyNameValueNode->EditValue != NULL) {
+ free (CopyNameValueNode->EditValue);
+ }
+ free (CopyNameValueNode);
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ StrCpy (CopyNameValueNode->Name, NameValueNode->Name);
+ StrCpy (CopyNameValueNode->Value, NameValueNode->Value);
+ StrCpy (CopyNameValueNode->EditValue, NameValueNode->EditValue);
+ //
+ // Insert it to StorageCopy->NameValueListHead
+ //
+ InsertTailList(&StorageCopy->NameValueListHead,&CopyNameValueNode->Link);
+ NameValueLink = GetNextNode (&Storage->NameValueListHead, NameValueLink);
+ }
+
+ //
+ // Insert it to StorageListHead1
+ //
+ InsertTailList(StorageListHead1,&StorageCopy->Link);
+ }
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the current defaultId and platfrom is equal to the first one of one
+ group of defaultId and platformId which have the same variable data.
+
+ @param DefaultId The default Id
+ @param PlatformId The platform Id
+
+ @retval TRUE If not equal to the first defaultId and platformId, return TRUE
+ @return EFI_ABORTED Others
+**/
+BOOLEAN
+NoTheKeyIdOfGroup (
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < mMultiPlatformParam.KeyIdNum; Index++) {
+ if (
+ (DefaultId == mMultiPlatformParam.KeyDefaultId[Index])
+ && (PlatformId == mMultiPlatformParam.KeyPlatformId[Index])
+ ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Evaluate the value in all formset according to the defaultId and platformId.
+
+ If not the multi-platform mode, the defaultId is 0. In this case, the
+ platform Id will be the default value of that question.
+
+ @param UpdateMode It will be TRUE in update Mode
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+EvaluateTheValueInFormset (
+ IN BOOLEAN UpdateMode
+ )
+{
+ EFI_STATUS Status;
+ UINT16 DefaultId;
+ UINT64 PlatformId;
+ UINT16 CurDefaultId;
+ UINT64 CurPlatformId;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ UINT32 Index;
+ UQI_PARAM_LIST *CurUqiList;
+
+ Status = EFI_SUCCESS;
+
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ ScanUqiFullList (mUqiList);
+
+ //
+ // Multi-platform mode support
+ //
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
+ PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (UpdateMode && NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+ //
+ // Initialize the Storage of mVarListEntry
+ //
+ ClearStorageEntryList (&mVarListEntry, DefaultId, PlatformId);
+
+ Status = ExtractDefault (
+ NULL,
+ NULL,
+ DefaultId,
+ PlatformId,
+ SystemLevel
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Clear the platformId as 0 after calculation.
+ //
+ Status = AssignThePlatformId (0);
+ if (EFI_ERROR (Status)) {
+ printf ("Failed to clear the platformid.\n");
+ return Status;
+ }
+ //
+ // Update the value from script file
+ //
+ if (UpdateMode) {
+ SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+ }
+ //
+ // If not existed the same variables in mAllVarListEntry, insert the new ones.
+ // Or else, only add the defaultId and platformId to the former one.
+ //
+ if (ComparePartSameVariableList (&mAllVarListEntry, &mVarListEntry, &CurDefaultId, &CurPlatformId)) {
+ AppendIdToVariables (&mAllVarListEntry, CurDefaultId, CurPlatformId, DefaultId, PlatformId);
+ } else {
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // In update mode, add the other defaultId and platform of a group to the variale list
+ //
+ if (UpdateMode) {
+ CurUqiList = mUqiList;
+
+ while (CurUqiList != NULL) {
+ if ((DefaultId == CurUqiList->Header.DefaultId[0])
+ && (PlatformId == CurUqiList->Header.PlatformId[0])
+ ) {
+ break;
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+
+ if (CurUqiList == NULL) {
+ return EFI_ABORTED;
+ }
+
+ for (Index = 1; Index < CurUqiList->Header.IdNum; Index++) {
+ CurDefaultId = CurUqiList->Header.DefaultId[Index];
+ CurPlatformId = CurUqiList->Header.PlatformId[Index];
+ AppendIdToVariables (&mAllVarListEntry, DefaultId, PlatformId, CurDefaultId, CurPlatformId);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ //
+ // General mode
+ //
+ Status = ExtractDefault (
+ NULL,
+ NULL,
+ 0,
+ 0,
+ SystemLevel
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // If existed the variable in NvStorage, copy them to mVarListEntry.
+ // Synchronize the default value from the EFI variable zone to variable list
+ //
+ Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
+ if (Status == EFI_INVALID_PARAMETER) {
+ Status = EFI_ABORTED;
+ return Status;
+ }
+ //
+ // Update the value from script file
+ //
+ if (UpdateMode) {
+ Status = SetUqiParameters (mUqiList,0, 0);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check and compare the value between the script file and variable from BFV.
+
+ It's used in the update operation of multi-plaform mode.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+CheckValueUpdateList (
+ VOID
+ )
+{
+ UINT16 DefaultId;
+ UINT64 PlatformId;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ EFI_STATUS Status;
+ FORMSET_STORAGE *Storage;
+ LIST_ENTRY *StorageLink;
+ UINT16 PreDefaultId;
+ UINT64 PrePlatformId;
+
+ Storage = NULL;
+ PreDefaultId = 0xFFFF;
+ PrePlatformId = 0xFFFFFFFFFFFFFFFF;
+
+ ScanUqiFullList (mUqiList);
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ StorageLink = GetFirstNode (&mBfvVarListEntry);
+ while (!IsNull (&mBfvVarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ continue;
+ } else {
+ PreDefaultId = Storage->DefaultId[0];
+ PrePlatformId = Storage->PlatformId[0];
+ }
+ DefaultId = PreDefaultId;
+ PlatformId = PrePlatformId;
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+ //
+ // Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
+ // the FormSet->StorageListHead.
+ //
+ DestroyAllStorage (&mVarListEntry);
+ Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ }
+ } else {
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
+ PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+ //
+ // Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
+ // the FormSet->StorageListHead.
+ //
+ DestroyAllStorage (&mVarListEntry);
+ Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
+
+ If not multi-platform mode, only return EFI_ABORTED.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ReadAllIfrToFromset (
+ IN VOID *Fv,
+ IN UINTN Length
+ )
+{
+ UINT8 NumberofMachingVfrBin;
+ UINTN *VfrBinBaseAddress;
+ UINTN *UniBinBaseAddress;
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_SECTION_STRUCT *EfiBufferHeader;
+ VOID *EfiAddr;
+
+ NumberofMachingVfrBin = 0;
+ VfrBinBaseAddress = NULL;
+ UniBinBaseAddress = NULL;
+ Status = EFI_SUCCESS;
+ EfiBufferHeader = NULL;
+ EfiAddr = NULL;
+
+ //
+ // Locate the efi base address
+ //
+ EfiBufferHeader = malloc (sizeof (EFI_SECTION_STRUCT));
+ if (EfiBufferHeader == NULL) {
+ return EFI_ABORTED;
+ }
+ memset (
+ EfiBufferHeader,
+ 0,
+ sizeof (EFI_SECTION_STRUCT)
+ );
+
+ Status = ParseSection (
+ TRUE,
+ (UINT8 *)Fv,
+ Length,
+ &EfiBufferHeader
+ );
+ if (Status != EFI_SUCCESS) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+ EfiAddr = (VOID *)EfiBufferHeader->BufferBase;
+ //
+ //Search the Offset at the end of FFS, whatever it is compressed or not
+ //
+ Status = SearchVfrBinInFFS (Fv, EfiAddr, Length, &VfrBinBaseAddress, &NumberofMachingVfrBin);
+ if (Status != EFI_SUCCESS) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ Status = SearchUniBinInFFS (
+ Fv,
+ EfiAddr,
+ Length,
+ &UniBinBaseAddress
+ );
+ if (Status != EFI_SUCCESS) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Read all Ifr information into Formset and Form structure
+ //
+ for (Index = 0; Index < NumberofMachingVfrBin; Index++) {
+ if ((EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *(VfrBinBaseAddress + Index)
+ || (EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *UniBinBaseAddress
+ ) {
+ printf ("Failed to locate Ifr data from efi by the offset.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ Status = ParseFormSetInVfrBin (
+ (UINTN **)VfrBinBaseAddress,
+ (UINTN *)*UniBinBaseAddress,
+ Index
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+
+Done:
+ //
+ // Free the memory which stores the offset
+ //
+ if (VfrBinBaseAddress != NULL) {
+ free (VfrBinBaseAddress);
+ }
+ if (UniBinBaseAddress != NULL) {
+ free (UniBinBaseAddress);
+ }
+ //
+ // Free the memory for uncompressed space in section
+ //
+ for (Index = 0; Index < EfiBufferHeader->UnCompressIndex; Index++) {
+ if ((VOID *)EfiBufferHeader->UncompressedBuffer[Index] != NULL) {
+ free ((VOID *)EfiBufferHeader->UncompressedBuffer[Index]);
+ }
+ }
+ return Status;
+}
+
+/**
+ Get next questions of four kinds in FormSet list.
+
+ If not one kinds of ONE_OF CHECK_BOX ORDER_LIST and NUMERIC, continue to parse next question.
+ If parse to the end of questions, return NULL.
+
+ @param FormSetEntryListHead the pointer to the LIST_ENTRY
+ @param OrderOfQuestion the order of question
+
+ @retval If succeed, return the pointer to the question
+ @return NULL
+**/
+FORM_BROWSER_STATEMENT *
+GetNextQuestion (
+ IN LIST_ENTRY *FormSetEntryListHead,
+ IN OUT UINT32 *OrderOfQuestion
+ )
+{
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ FORM_BROWSER_FORM *Form;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ UINT32 Index;
+
+ FormSet = NULL;
+ FormSetLink = NULL;
+ Form = NULL;
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ Index = 0;
+
+ FormSetLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ // Parse all forms in formset
+ //
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (*OrderOfQuestion == Index++) {
+ (*OrderOfQuestion)++;
+ return Question;
+ }
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ }
+ return NULL;
+}
+
+/**
+ Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
+
+ If not multi-platform mode, only return EFI_ABORTED.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ReadDefaultAndPlatformId (
+ IN LIST_ENTRY *FormSetEntryListHead
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormLink;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ LIST_ENTRY *DefaultStoreLink;
+ FORM_BROWSER_STATEMENT *CurQuestion;
+ UINT32 MatchedNum;
+ UINT32 QuestionOrder;
+
+ Status = EFI_SUCCESS;
+ CurQuestion = NULL;
+ MatchedNum = 0;
+ QuestionOrder = 0;
+ //
+ //Check whether it is the Multi-Platform solution or not
+ //
+ if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ //
+ // Read defaultId from FormSet List
+ //
+ FormLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
+ //
+ // Parse Default Store in formset
+ //
+ DefaultStoreLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+ while (!IsNull (&FormSet->DefaultStoreListHead, DefaultStoreLink)) {
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultStoreLink);
+ StoreAllDefaultId (DefaultStore->DefaultId);
+ DefaultStoreLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultStoreLink);
+ }
+ FormLink = GetNextNode (FormSetEntryListHead, FormLink);
+ }
+
+ //
+ //Read the platformId from FormSetList
+ //
+ while ((CurQuestion = GetNextQuestion (FormSetEntryListHead, &QuestionOrder)) != NULL) {
+ Status = ReadPlaformId (CurQuestion);
+ if (!EFI_ERROR (Status)) {
+ MatchedNum++;
+ }
+ }
+
+ if (MatchedNum == 0) {
+ printf ("There are no questions included in the platformid in the FD.");
+ Status = EFI_ABORTED;
+ } else if (MatchedNum > 1) {
+ printf ("There are %d questions included in the platformid in the FD.", MatchedNum);
+ Status = EFI_ABORTED;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+
+ return Status;
+}
+
+/**
+ Read the first two bytes to check whether it is Ascii or UCS2.
+
+ @param ScriptFile Pointer to the script file.
+
+ @reture TRUE If ascii, return TRUE
+ @reture FALSE Others, return FALSE.
+
+**/
+FILE_TYPE
+IsAsciiOrUcs2 (
+ IN FILE *ScriptFile
+ )
+{
+ CHAR16 FirstTwoBytes;
+
+ fread(&FirstTwoBytes, 1, 2, ScriptFile);
+
+ if (FirstTwoBytes == BigUnicodeFileTag) {
+ return BIG_UCS2;
+ } else if (FirstTwoBytes == LittleUnicodeFileTag) {
+ return LITTLE_UCS2;
+ } else {
+ return ASCII;
+ }
+}
+
+/**
+ Read Unicode characters and transfer it to ASCII.
+
+ @param ScriptFile The pointer to the script file.
+ @param Type The type of BigUCS2 or LittleUCS2
+
+ @return The ASCII characters
+
+**/
+CHAR8 *
+ReadUcs2ToStr (
+ IN OUT FILE *ScriptFile,
+ IN FILE_TYPE Type
+)
+{
+ CHAR16 TempChar16;
+ CHAR16 TempChar8;
+ CHAR8 *StrChar8;
+ UINTN Index;
+ BOOLEAN FirstParse;
+
+ TempChar16 = L'\0';
+ TempChar8 = '\0';
+ StrChar8 = NULL;
+ Index = 0;
+ FirstParse = TRUE;
+
+ if (ScriptFile == NULL) {
+ return NULL;
+ }
+ StrChar8 = calloc (MAX_STR_LEN_FOR_PICK_UQI, sizeof (CHAR8));
+ assert (StrChar8);
+
+ for (Index = 0; Index < MAX_STR_LEN_FOR_PICK_UQI; Index++) {
+ //
+ // The first parse should skip the 0x0020 (BigUCS2) or 0x2000 (LittleUCS2)
+ //
+ if (FirstParse) {
+ do {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ } while ((TempChar16 == 0x0020) || (TempChar16 == 0x2000));
+ FirstParse = FALSE;
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ }
+ //
+ // Read until break the "Space"
+ //
+ if ((TempChar16 == 0x0020) || (TempChar16 == 0x2000)) {
+ break;
+ }
+ if (Type == BIG_UCS2) {
+ TempChar8 = (CHAR8)TempChar16;
+ } else {
+ TempChar8 = (CHAR8)(TempChar16 >> 8);
+ }
+ memcpy (StrChar8 + Index, &TempChar8, 0x1);
+ }
+ if (Index == MAX_STR_LEN_FOR_PICK_UQI) {
+ free (StrChar8);
+ return NULL;
+ }
+ *(StrChar8 + Index) = '\0';
+
+ return StrChar8;
+}
+
+/**
+ Read Unicode characters and transfer it to ASCII.
+
+ @param AsciiStr The pointer to the Ascii string. It may inlcudes blank space.
+ @param IdArray The pointer to the array of Id.
+
+ @return The number of default or platform Id
+
+**/
+static
+UINT16
+GetNumFromAsciiString (
+ IN CHAR8 *AsciiStr,
+ IN OUT UINT64 *IdArray
+)
+{
+ UINT16 Index1;
+ UINT16 Index2;
+ UINT16 NumofId;
+ CHAR8 CharArray[16];
+ BOOLEAN ExistedValue;
+
+ Index1 = 0;
+ Index2 = 0;
+ NumofId = 0;
+ ExistedValue = FALSE;
+
+ while (*(AsciiStr + Index1) != '\n') {
+
+ Index2 = 0;
+ ExistedValue = FALSE;
+ memset (CharArray, 0, 16);
+ for (; *(AsciiStr + Index1) == ' '; Index1++);
+ for (; (*(AsciiStr + Index1) != ' ') && (*(AsciiStr + Index1) != '\n'); Index1++) {
+ assert (Index2 <= 15);
+ *(CharArray + Index2++) = *(AsciiStr + Index1);
+ ExistedValue = TRUE;
+ }
+ if (ExistedValue && (*(AsciiStr + Index1 - 1) != '\n')) {
+ sscanf(CharArray, "%lld", (long long *)&IdArray[NumofId++]);
+ }
+ }
+ return NumofId;
+}
+
+/**
+ Parse the script file to build the linked list of question structures.
+
+ Pick up the UQI information and save it to the UqiList. The current scripts
+ could be Ascii or UCS2 (Little or Big Mode).
+
+ @param ScriptFile The pointer to the script file.
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER ScriptFile is NULL
+
+**/
+static
+EFI_STATUS
+PickUpUqiFromScript (
+ IN FILE *ScriptFile
+ )
+{
+ CHAR8 TempChar;
+ BOOLEAN InQuote;
+ CHAR16 TempChar16;
+ UINT32 UqiSize;
+ CHAR16 *UqiBuffer;
+ CHAR8 Type[32];
+ UINT16 Index;
+ UQI_PARAM_LIST *UqiNode;
+ UINTN MaxContainers;
+ UINT32 ScriptsLine;
+ FILE_TYPE AsciiOrUcs2;
+ CHAR8 *Char8Str;
+ CHAR8 DefaultIdStr[30];
+ CHAR8 PlatformIdStr[30];
+ CHAR8 PlatformUqi[30];
+ UINT16 Index1;
+ UINT16 Index2;
+ UINT16 Index3;
+ UINT16 Index4;
+ UINT16 Index5;
+ BOOLEAN ReadDefaultId;
+ BOOLEAN ReadPlatformId;
+ BOOLEAN ReadPlatformIdUqi;
+ UINT64 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT64 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 DefaultIdNum;
+ UINT16 PlatformIdNum;
+ UINT8 Array[MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 IdStart;
+ UINT16 IdEnd;
+
+ Char8Str = NULL;
+ ScriptsLine = 0;
+ AsciiOrUcs2 = ASCII;
+ Index1 = 0;
+ Index2 = 0;
+ Index3 = 0;
+ Index4 = 0;
+ Index5 = 0;
+ ReadDefaultId = FALSE;
+ ReadPlatformId = FALSE;
+ ReadPlatformIdUqi = FALSE;
+ DefaultIdNum = 1;
+ PlatformIdNum = 1;
+ InQuote = FALSE;
+
+ memset (DefaultId, 0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ memset (PlatformId, 0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ memcpy (DefaultIdStr, "/ FCEKEY DEFAULT_ID:", strlen ("/ FCEKEY DEFAULT_ID:") + 1);
+ memcpy (PlatformIdStr,"/FCEKEY PLATFORM_ID:", strlen ("/FCEKEY PLATFORM_ID:") + 1);
+ memcpy (PlatformUqi, "/FCEKEY PLATFORM_UQI:", strlen ("/FCEKEY PLATFORM_UQI:") + 1);
+
+ if (ScriptFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check the file type
+ //
+ AsciiOrUcs2 = IsAsciiOrUcs2 (ScriptFile);
+ if (AsciiOrUcs2 == ASCII) {
+ fseek (ScriptFile, 0, SEEK_SET);
+ }
+
+ while(!feof(ScriptFile)) {
+ //
+ // Reset local data
+ //
+ TempChar = '\0';
+ TempChar16 = L'\0';
+ UqiSize = 0;
+ UqiBuffer = NULL;
+ MaxContainers = 0;
+ UqiNode = NULL;
+ memset(Type, 0, 32);
+ //
+ // Read first character of the line to find the line type
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ //
+ // Take "\n\r" one line
+ //
+ if (TempChar != 0x0d) {
+ ScriptsLine++;
+ }
+ switch (TempChar) {
+
+ case 'Q':
+ //
+ // Process question line
+ //
+ // Read size of UQI string
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %x", (INT32 *)&UqiSize);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %x", (INT32 *)&UqiSize);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (UqiSize > MAX_INPUT_ALLOCATE_SIZE) {
+ return EFI_ABORTED;
+ }
+ if (UqiSize == 0) {
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+ }
+ //
+ // Malloc buffer for string size + null termination
+ //
+ UqiBuffer = (CHAR16 *)calloc(UqiSize + 1, sizeof(CHAR16));
+
+ if (UqiBuffer == NULL) {
+ printf("Error. Unable to allocate 0x%04lx bytes for UQI string -- FAILURE\n", (unsigned long)((UqiSize + 1) * sizeof(CHAR16)));
+ break;
+ }
+ //
+ // Read UQI string
+ //
+ for (Index = 0; Index < UqiSize; Index++) {
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %hx", (short *)&(UqiBuffer[Index]));
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ free (UqiBuffer );
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %hx", (short *)&(UqiBuffer[Index]));
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ }
+ //
+ // Set null termination
+ //
+ UqiBuffer[Index] = 0;
+ //
+ // Read question type
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, "%31s", Type);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %31s", Type);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (stricmp(Type, "ONE_OF") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = ONE_OF;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf("Fail to allocate memory");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf("Fail to allocate memory");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+
+ } else if (stricmp(Type, "CHECKBOX") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = CHECKBOX;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+
+ } else if (stricmp(Type, "STRING") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+
+ UqiNode->Header.Type = STRING;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+ InQuote = FALSE;
+ IdStart = 0;
+ IdEnd = 0;
+ for (Index = 0; Index < MAX_INPUT_ALLOCATE_SIZE; Index ++) {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ if (TempChar == '\"') {
+ if (InQuote == TRUE) {
+ InQuote = FALSE;
+ IdEnd = Index;
+ } else {
+ InQuote = TRUE;
+ IdStart = Index;
+ }
+ }
+ if (Index > IdStart) {
+ if (InQuote == FALSE) {
+ break;
+ }
+ *(UqiNode->Header.Value + Index - IdStart -1) = TempChar;
+ Index ++;
+ }
+
+ }
+ if (IdEnd < IdStart) {
+ printf("The STRING is not end with \" character!\n");
+ return EFI_ABORTED;
+ }
+ if (IdStart == 0) {
+ printf("The STRING is not start with \" character!\n");
+ return EFI_ABORTED;
+ }
+
+ } else if (stricmp(Type, "NUMERIC") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = NUMERIC;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+
+ } else if (stricmp(Type, "ORDERED_LIST") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = ORDERED_LIST;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %x", (INT32 *)&MaxContainers);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %x", (INT32 *)&MaxContainers);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (MaxContainers > MAX_INPUT_ALLOCATE_SIZE) {
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Value = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *UqiNode->Header.Value = (UINT8) MaxContainers;
+ *UqiNode->Header.DiffValue = (UINT8) MaxContainers;
+
+ for (Index = 1; Index <= MaxContainers; Index++) {
+ if (*(UqiNode->Header.Value + Index) == '/') {
+ printf ("Error. Failed to parse the value of ORDERED_LIST.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", ((long long *)UqiNode->Header.Value + Index));
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", ((long long *)UqiNode->Header.Value + Index));
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ }
+
+ } else {
+ //
+ // Unknown type
+ //
+ // Free UQI buffer before skipping to next line
+ //
+ free(UqiBuffer);
+ UqiBuffer = NULL;
+ printf ("Error. Invalid parameters exist in scripts line %d", ScriptsLine);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.ScriptsLine = ScriptsLine;
+ //
+ // Skip to next line
+ //
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+
+ case '\n':
+ case '\r':
+ //
+ // Newline, skip to next character
+ //
+ break;
+
+ case '/':
+ //
+ // Get the value of PlatformId and DefaultId from comments
+ //
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ //
+ //"/ DefaultId :"
+ //
+ if (!ReadDefaultId) {
+ if (TempChar == DefaultIdStr[Index1]) {
+ Index1++;
+ } else {
+ Index1 = 0;
+ }
+ if (Index1 == strlen (DefaultIdStr)) {
+ Index1 = 0;
+ Index3 = 0;
+ memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+ ReadDefaultId = TRUE;
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ }
+ } else if (ReadDefaultId) {
+ if (TempChar == '\n') {
+ ReadDefaultId = FALSE;
+ Array[Index3] = TempChar;
+ DefaultIdNum = GetNumFromAsciiString ((CHAR8 *)Array, DefaultId);
+ mMultiPlatformParam.KeyDefaultId[mMultiPlatformParam.KeyIdNum] = (UINT16)DefaultId[0];
+ } else {
+ Array[Index3++] = TempChar;
+ }
+ }
+ //
+ //"/ PlatformId:"
+ //
+ if (!ReadPlatformId) {
+ if (TempChar == PlatformIdStr[Index2]) {
+ Index2++;
+ } else {
+ Index2 = 0;
+ }
+ if (Index2 == strlen (PlatformIdStr)) {
+ Index2 = 0;
+ Index3 = 0;
+ memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+ ReadPlatformId = TRUE;
+ }
+ } else if (ReadPlatformId) {
+ if (TempChar == '\n') {
+ ReadPlatformId = FALSE;
+ Array[Index3] = TempChar;
+ PlatformIdNum = GetNumFromAsciiString ((CHAR8 *)Array, PlatformId);
+ //
+ // Take the first defaultid an platformid as the key of this group
+ //
+ mMultiPlatformParam.KeyPlatformId[mMultiPlatformParam.KeyIdNum++] = PlatformId[0];
+ assert (DefaultIdNum == PlatformIdNum);
+ } else {
+ Array[Index3++] = TempChar;
+ }
+ }
+ //
+ //"/ PlatformIdUqi:"
+ //
+ if (!ReadPlatformIdUqi) {
+ if (TempChar == PlatformUqi[Index4]) {
+ Index4++;
+ } else {
+ Index4 = 0;
+ }
+ if (Index4 == strlen (PlatformUqi)) {
+ Index4 = 0;
+ Index3 = 0;
+ memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+ ReadPlatformIdUqi = TRUE;
+ }
+ } else if (ReadPlatformIdUqi) {
+ if (mMultiPlatformParam.Uqi.HexNum > 0) {
+ continue;
+ }
+ //
+ // Read size of UQI string
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (mMultiPlatformParam.Uqi.HexNum > MAX_INPUT_ALLOCATE_SIZE) {
+ return EFI_ABORTED;
+ }
+ //
+ // Malloc buffer for string size + null termination
+ //
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ free (mMultiPlatformParam.Uqi.Data);
+ mMultiPlatformParam.Uqi.Data = NULL;
+ }
+ mMultiPlatformParam.Uqi.Data = (CHAR16 *)calloc(mMultiPlatformParam.Uqi.HexNum + 1, sizeof(CHAR16));
+
+ if (mMultiPlatformParam.Uqi.Data == NULL) {
+ printf("Error. Unable to allocate 0x%04zx bytes for UQI string -- FAILURE\n", (mMultiPlatformParam.Uqi.HexNum + 1) * sizeof(CHAR16));
+ break;
+ }
+ //
+ // Read UQI string
+ //
+ for (Index = 0; Index < mMultiPlatformParam.Uqi.HexNum; Index++) {
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ }
+ //
+ // Set null termination
+ //
+ mMultiPlatformParam.Uqi.Data[Index] = 0;
+ ReadPlatformIdUqi = FALSE;
+ }
+
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+ //
+ // To do: Get and set DefaultId and PlatformId here!
+ //
+ default:
+ //
+ // Comment or garbage, skip to next line
+ //
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the offset of file name from the whole path.
+
+ @param NameStr The whole file path.
+
+ @retval Offset Return the offset of file name in path
+**/
+static
+UINTN
+GetOffsetOfFileName (
+ IN CHAR8 *NameStr
+ )
+{
+ CHAR8 *Str;
+ UINTN Index;
+ UINTN CurIndex;
+
+ Index = 0;
+ CurIndex = 0;
+ Str = NameStr;
+
+ if (NameStr == NULL) {
+ return 0;
+ }
+ while (*Str != '\0') {
+ if (*Str == OS_SEP) {
+ CurIndex = Index;
+ }
+ Str++;
+ Index++;
+ }
+ if (*(NameStr + CurIndex) == OS_SEP) {
+ return CurIndex + 1;
+ } else {
+ return 0;
+ }
+}
+/**
+ Print the questions which is updated to the current platform successfully.
+
+ Parse the Uqi List, and print it till break NULL.
+
+ @param List Pointer to a List.
+
+ @retval EFI_SUCCESS The Print was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+VOID
+PrintUpdateListInfo (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ UINT32 Index;
+ UINT32 Index1;
+ UINT32 Index2;
+ UQI_PARAM_LIST *CurList;
+
+ Index1 = 0;
+ Index2 = 0;
+ Index = 0;
+ CurList = UqiList;
+
+ printf ("\n\n -- Update List -- ");
+
+ while (CurList != NULL) {
+ if (!CurList->ErrorOrNot && CurList->ParseOrNot && !CurList->SameOrNot) {
+ ++Index;
+ printf ("\n\n[Script line %d] Update No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
+ printf ("Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ //
+ //Print the value of scripts
+ //
+ printf ("\n[ Update Value From: ");
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
+ printf ("%02x ", *(CurList->Header.DiffValue + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
+ }
+ //
+ //Print the value of current platform
+ //
+ printf (" To: ");
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
+ printf ("%02x ", *(CurList->Header.Value + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+ }
+ printf ("]");
+ }
+ CurList = CurList->Next;
+ }
+ if (Index > 1) {
+ printf ("\n\n\n[Results]: %d questions have been updated successfully in total. \n", Index);
+ } else {
+ printf ("\n\n\n[Results]: %d question has been updated successfully in total. \n", Index);
+ }
+}
+
+
+/**
+ Print the error, when update questions.
+
+ Parse the Uqi List, and print it till break NULL.
+
+ @param List The Pointer to a List.
+
+**/
+static
+BOOLEAN
+PrintErrorInfo (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ UINT32 Index1;
+ UINT32 Index2;
+ UINT32 Index;
+ UQI_PARAM_LIST *CurList;
+ BOOLEAN IsError;
+
+ Index1 = 0;
+ Index2 = 0;
+ Index = 0;
+ CurList = UqiList;
+ IsError = FALSE;
+
+ while (CurList != NULL) {
+ if (CurList->ErrorOrNot && CurList->ParseOrNot) {
+ IsError = TRUE;
+ ++Index;
+ printf ("\n\n[Script line %d] Error Information No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
+ printf ("Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ //
+ //Print the Input value of scripts
+ //
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *CurList->Header.Value; Index2++) {
+ printf ("%02x ", *(CurList->Header.Value + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+ }
+ //
+ //Print the Error information
+ //
+ if (CurList->Error != NULL) {
+ printf ("\n%s ", CurList->Error);
+ }
+ }
+ CurList = CurList->Next;
+ }
+ if (IsError) {
+ if (Index > 1) {
+ printf ("\n\n[Results]: Occurred %d errors during the update process. \n", Index);
+ } else {
+ printf ("\n\n[Results]: Occurred %d error during the update process. \n", Index);
+ }
+ }
+ return IsError;
+}
+
+/**
+ Any questions that exist in both the script and the current platform and have
+ different values will be logged to the screen.
+
+ Parse the Uqi List, and print it till break NULL.
+
+ @param List Pointer to a List.
+
+ @retval EFI_SUCCESS The Print was complete successfully
+ @return EFI_ABORTED An error occurreds
+**/
+static
+VOID
+PrintVerifiedListInfo (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ UINT32 Index1;
+ UINT32 Index2;
+ UINT32 Index3;
+ UINT32 Index;
+ UQI_PARAM_LIST *CurList;
+ UINT32 StrLen;
+ UINT32 StrLen1;
+ UINT32 StrLen2;
+
+ Index1 = 0;
+ Index2 = 0;
+ Index = 0;
+ StrLen = 0;
+ CurList = UqiList;
+
+ StrLen1 = strlen (mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
+ StrLen2 = strlen (mInputFdName + GetOffsetOfFileName (mInputFdName));
+
+ StrLen = (StrLen1 > StrLen2) ? StrLen1:StrLen2;
+
+ printf ("\n\n -- Different List -- ");
+
+ while (CurList != NULL) {
+ if (!CurList->SameOrNot && CurList->ParseOrNot) {
+ ++Index;
+ printf ("\n\n[Script line %d] Difference No.%d:", CurList->Header.ScriptsLine, ++Index1);
+ printf ("\n[%s", mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
+ for (Index3 = 0; Index3 < StrLen - StrLen1; Index3++) {
+ printf (" ");
+ }
+ printf ("]:");
+ printf (" Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ //
+ //Print the Input value of scripts
+ //
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
+ printf ("%02x ", *(CurList->Header.Value + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+ }
+ //
+ //Print the value of current platform
+ //
+ printf ("\n[%s", mInputFdName + GetOffsetOfFileName (mInputFdName));
+ for (Index3 = 0; Index3 < StrLen - StrLen2; Index3++) {
+ printf (" ");
+ }
+ printf ("]:");
+ printf (" Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
+ printf ("%02x ", *(CurList->Header.DiffValue + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
+ }
+ }
+ CurList = CurList->Next;
+ }
+ if (Index > 1) {
+ printf (
+ "\n\n\n[Results]: There are %d differences between '%s' and '%s' in total.\n\n\n",
+ Index,
+ mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
+ mInputFdName + GetOffsetOfFileName (mInputFdName)
+ );
+ } else {
+ printf (
+ "\n\n\n[Results]: There is %d difference between '%s' and '%s' in total.\n\n\n",
+ Index,
+ mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
+ mInputFdName + GetOffsetOfFileName (mInputFdName)
+ );
+ }
+}
+
+/**
+ Insert Uqi object to the end of unidirection List.
+
+ @param InList The Pointer to the current object
+ @param UqiListEntry The pointer to the entry of UqiList
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertUnidirectionList (
+ IN UQI_PARAM_LIST *InList,
+ IN UQI_PARAM_LIST **UqiListEntry
+ )
+{
+ UQI_PARAM_LIST **UqiCurList;
+ UQI_PARAM_LIST *UqiNext;
+
+ UqiCurList = NULL;
+ UqiNext = NULL;
+
+ if (UqiListEntry == NULL) {
+ return EFI_ABORTED;
+ }
+ //
+ // Insert to Uqi Node to UqiList
+ //
+ UqiCurList = UqiListEntry;
+ UqiNext = *UqiCurList;
+ if (UqiNext == NULL) {
+ //
+ //Insert is the first node as node header
+ //
+ *UqiCurList = InList;
+ } else {
+ while ((UqiNext != NULL) && (UqiNext->Next != NULL)) {
+ UqiNext = UqiNext->Next;
+ }
+ UqiNext->Next = InList;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Free variable unidirection List.
+
+ @param UqiListEntry The pointer to the entry of UqiList
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+FreeUnidirectionList (
+ IN UQI_PARAM_LIST *UqiListEntry
+ )
+{
+ UQI_PARAM_LIST *Next;
+
+ Next = NULL;
+ //
+ // Free Uqi List
+ //
+ while (UqiListEntry != NULL) {
+ Next = UqiListEntry->Next;
+ if (UqiListEntry->Header.Value != NULL) {
+ free (UqiListEntry->Header.Value);
+ }
+ if (UqiListEntry->Header.DiffValue != NULL) {
+ free (UqiListEntry->Header.DiffValue);
+ }
+ if (UqiListEntry->Header.Data != NULL) {
+ free (UqiListEntry->Header.Data);
+ }
+ if (UqiListEntry->Header.DefaultId != NULL) {
+ free (UqiListEntry->Header.DefaultId);
+ }
+ if (UqiListEntry->Header.PlatformId != NULL) {
+ free (UqiListEntry->Header.PlatformId);
+ }
+ if (UqiListEntry->Error != NULL) {
+ free (UqiListEntry->Error);
+ }
+ free (UqiListEntry);
+ UqiListEntry = Next;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a directory and files in it.
+
+ @param DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+ if (DirName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete a directory and files in it.
+ //
+
+ SystemCommand = malloc (
+ strlen (RMDIR_STR) +
+ strlen (DirName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ RMDIR_STR,
+ DirName
+ );
+
+ system (SystemCommand);
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pick up the FFS from the FD image.
+
+ Call BfmLib to get all FFS in one FD image, and save all which includes IFR
+ Binary to gEfiFdInfo structure.
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+static
+EFI_STATUS
+PickUpFfsFromFd (
+ VOID
+ )
+{
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ CHAR8 *TempSystemCommand;
+ CHAR8 *TemDir;
+ EFI_STATUS Status;
+ INT32 ReturnValue;
+
+ Status = EFI_SUCCESS;
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ TempSystemCommand = NULL;
+ TemDir = NULL;
+ ReturnValue = 0;
+
+ memset (&gEfiFdInfo, 0, sizeof (G_EFI_FD_INFO));
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "BfmLib -e \"%s\" ";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ printf ("Fail to allocate memory.\n");
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ "BfmLib -e \"%s\" ",
+ mInputFdName
+ );
+
+ if (mFullGuidToolDefinitionDir[0] != 0) {
+ TempSystemCommand = SystemCommand;
+ SystemCommand = malloc (
+ strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (TempSystemCommand) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ free (TempSystemCommand);
+ return EFI_UNSUPPORTED;
+ }
+ strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+ strcat (SystemCommand, OS_SEP_STR);
+ strcat (SystemCommand, TempSystemCommand);
+ free (TempSystemCommand);
+
+ }
+
+ //
+ // Call BfmLib to get all FFS in Temp folder of current path
+ //
+ ReturnValue = system (SystemCommand);
+ free (SystemCommand);
+ if (ReturnValue == -1) {
+ printf ("Error. Call BfmLib failed.\n");
+ return EFI_ABORTED;
+ }
+ //
+ //Pick up the FFS which is interrelated with the IFR binary.
+ //
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME)> _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ mMultiPlatformParam.ExistStorageFfsInBfv = FALSE;
+ Status = FindFileInFolder (TemDir, &mMultiPlatformParam.ExistStorageFfsInBfv, &mMultiPlatformParam.SizeOptimized);
+
+ return Status;
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+/**
+ Generate pre-defined guided tools data.
+
+ @return An EFI_HANDLE contain guided tools data.
+
+**/
+static
+EFI_HANDLE
+PreDefinedGuidedTools (
+ VOID
+)
+{
+ EFI_GUID Guid;
+ STRING_LIST *Tool;
+ GUID_SEC_TOOL_ENTRY *FirstGuidTool;
+ GUID_SEC_TOOL_ENTRY *LastGuidTool;
+ GUID_SEC_TOOL_ENTRY *NewGuidTool;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
+ "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
+ "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
+ "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
+ "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
+ };
+
+ Tool = NULL;
+ FirstGuidTool = NULL;
+ LastGuidTool = NULL;
+ NewGuidTool = NULL;
+
+ for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
+ Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
+ if ((Tool != NULL) &&
+ (Tool->Count == 3)
+ ) {
+ Status = StringToGuid (Tool->Strings[0], &Guid);
+ if (!EFI_ERROR (Status)) {
+ NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
+ if (NewGuidTool != NULL) {
+ memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
+ NewGuidTool->Name = CloneString(Tool->Strings[1]);
+ NewGuidTool->Path = CloneString(Tool->Strings[2]);
+ NewGuidTool->Next = NULL;
+ } else {
+ printf ( "Fail to allocate memory. \n");
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ }
+ return NULL;
+ }
+ if (FirstGuidTool == NULL) {
+ FirstGuidTool = NewGuidTool;
+ } else {
+ LastGuidTool->Next = NewGuidTool;
+ }
+ LastGuidTool = NewGuidTool;
+ }
+
+ } else {
+ fprintf (stdout, "Error");
+ }
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ Tool = NULL;
+ }
+ }
+ return FirstGuidTool;
+}
+
+/**
+ Read all storages under a specified platformId and defaultId from BFV.
+
+ @param Binary The pointer to the buffer of binary.
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadStorageFromBinary (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ UINT32 Length;
+ UINT8 *DataBase;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ Length = 0;
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ //
+ // Judge the layout of NV by Variable Guid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore ((VOID *)(DataBase + *(UINT16 *)DataBase));
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot ((VOID *)(DataBase + *(UINT16 *)DataBase));
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Read variable with Monotonic based layout from binary
+ //
+ Length = ReadMonotonicBasedVariableToList (Binary, StorageListEntry);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Read variable with time-based layout from binary
+ //
+ Length = ReadTimeBasedVariableToList (Binary, StorageListEntry);
+ } else {
+ //
+ // Read variable with normal layout from binary
+ //
+ Length = ReadVariableToList (Binary, StorageListEntry);
+ }
+
+ return Length;
+}
+
+/**
+ Insert one storage to the raw bianry, and return its length.
+
+ @param Storage The pointer to a storage in storage list.
+ @param Binary The pointer to the buffer of binary.
+
+ @return length The length of storage
+**/
+UINT32
+PutStorageToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ UINT32 Length;
+ UINT32 Index;
+ UINT8 *BinaryBeginning;
+ FORMSET_STORAGE *CurStorage;
+ LIST_ENTRY *StorageLink;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ Length = 0;
+ Index = 0;
+ BinaryBeginning = Binary;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+ //
+ // Build the binary for BFV
+ //
+ StorageLink = GetFirstNode (StorageListEntry);
+
+ while (!IsNull (StorageListEntry, StorageLink)) {
+ CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if ((CurStorage->DefaultId[0] == Storage->DefaultId[0])
+ && (CurStorage->PlatformId[0] == Storage->PlatformId[0])
+ && !CurStorage->Skip
+ ) {
+ CurStorage->Skip = TRUE;
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Copy variable with Monotonic based layout to binary
+ //
+ Length = CopyMonotonicBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Copy variable with time-based layout to binary
+ //
+ Length = CopyTimeBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
+ } else {
+ //
+ // Copy variable with normall layout to binary
+ //
+ Length = CopyVariableToBinary (CurStorage, BinaryBeginning, Index);
+ }
+ Index++;
+ }
+ StorageLink = GetNextNode (StorageListEntry, StorageLink);
+ }
+ //
+ // Fix the length of storage header under a specified DefaultId and PlatformId
+ //
+ if (AuthencitatedMonotonicOrNot) {
+ FixMontonicVariableHeaderSize (BinaryBeginning, Length);
+ } else if (AuthencitatedBasedTimeOrNot){
+ FixBasedTimeVariableHeaderSize (BinaryBeginning, Length);
+ } else {
+ FixVariableHeaderSize (BinaryBeginning, Length);
+ }
+ return Length;
+}
+
+/**
+ Insert one storage to Fd's NvStoreDatabase, and return its length.
+
+ @param Storage The pointer to a storage in storage list.
+ @param Binary The pointer to the buffer of binary.
+
+ @return length The length of storage
+**/
+UINT32
+PutStorageToNvStoreBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ UINT32 Length;
+ UINT32 Index;
+ UINT8 *BinaryBeginning;
+ FORMSET_STORAGE *CurStorage;
+ LIST_ENTRY *StorageLink;
+
+ Length = 0;
+ Index = 0;
+ BinaryBeginning = Binary;
+ //
+ // Build the binary for NvStorDatabase
+ //
+ StorageLink = GetFirstNode (StorageListEntry);
+ while (!IsNull (StorageListEntry, StorageLink)) {
+ CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if ((CurStorage->PlatformId[0] == Storage->PlatformId[0])
+ && (CurStorage->DefaultId[0] == Storage->DefaultId[0])
+ && !CurStorage->Skip
+ ) {
+ CurStorage->Skip = TRUE;
+ Length = CopyVariableToNvStoreBinary (CurStorage, BinaryBeginning, Index);
+ Index++;
+ }
+ StorageLink = GetNextNode (StorageListEntry, StorageLink);
+ }
+ // Alignment
+ Length = (Length + 3) & ~3;
+ FixNvStoreVariableHeaderSize (BinaryBeginning, Length);
+ return Length;
+}
+
+/**
+ Optimize the Delta binary size based on the default setting binary, and
+ create a new binary with new size on the Storage.ffs.
+
+ @param DefaultBinary The pointer to a default setting binary
+ @param DefaultHeaderLen The header lenght of default setting binary
+ @param DeltaBinary The pointer to a delta setting binary
+ @param CurrentSize The size of current delta data.
+
+ @return length The length of new storage
+**/
+UINT32
+OptimizeStorageDeltaData (
+ IN UINT8 *DefaultBinary,
+ IN UINT8 *CurrentBinary,
+ IN OUT UINT8 *DeltaBinary,
+ IN UINT32 CurrentSize
+ )
+{
+ UINT32 Size;
+ UINT16 Index;
+ UINT32 DefaultHeaderSize;
+ UINT32 DeltaHeaderSize;
+ UINT32 AlignSize;
+ PCD_DATA_DELTA DeltaData;
+ DefaultHeaderSize = ((PCD_DEFAULT_DATA *)DefaultBinary)->HeaderSize + 4;
+ DeltaHeaderSize = ((PCD_DEFAULT_DATA *)CurrentBinary)->HeaderSize + 4;
+ //
+ // Copy the Delta Header directly
+ //
+ Size = DeltaHeaderSize;
+ memcpy (DeltaBinary, CurrentBinary, Size);
+ //
+ // Compare the delta data and optimize the size
+ //
+ for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
+ if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
+ DeltaData.Offset = Index;
+ DeltaData.Value = *(CurrentBinary + DeltaHeaderSize + Index);
+ memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
+ Size = Size + sizeof(DeltaData);
+ }
+ }
+ *(UINT32 *)DeltaBinary = Size;
+ AlignSize = (Size + 7) & ~7;
+ //set Alignment data 0x00
+ for (Index = 0; Index < AlignSize - Size; Index++){
+ *(DeltaBinary + Size + Index) = 0x0;
+ }
+ return Size;
+}
+
+/**
+ Optimize the Delta binary size based on the default setting binary, and
+ create a new binary with new size on the Storage.ffs.
+
+ @param DefaultBinary The pointer to a default setting binary
+ @param DefaultHeaderLen The header lenght of default setting binary
+ @param DeltaBinary The pointer to a delta setting binary
+ @param CurrentSize The size of current delta data.
+
+ @return length The length of new storage
+**/
+UINT32
+OptimizeStorageSection (
+ IN UINT8 *DefaultBinary,
+ IN UINT8 *CurrentBinary,
+ IN OUT UINT8 *DeltaBinary,
+ IN UINT32 CurrentSize
+ )
+{
+ UINT32 Size;
+ UINT16 Index;
+ UINT32 DefaultHeaderSize;
+ UINT32 DeltaHeaderSize;
+ DATA_DELTA DeltaData;
+
+ DefaultHeaderSize = *(UINT16 *)DefaultBinary;
+ DeltaHeaderSize = *(UINT16 *)CurrentBinary;
+
+ //
+ // Copy the Delta Header directly
+ //
+ Size = DeltaHeaderSize;
+ memcpy (DeltaBinary, CurrentBinary, Size);
+ //
+ // Compare the delta data and optimize the size
+ //
+ for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
+ if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
+ DeltaData.Offset = Index;
+ DeltaData.Value = *(CurrentBinary + DeltaHeaderSize + Index);
+ memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
+ Size = Size + sizeof(DeltaData);
+ }
+ }
+ return Size;
+}
+
+/**
+ Create the storage section and copy it to memory.
+
+ @param Buffer The pointer to the buffer
+ @param Size The size of input buffer.
+
+ @return the new size
+**/
+UINT32
+CreateStorageSection (
+ IN OUT UINT8 *Buffer,
+ IN UINT32 Size,
+ IN CHAR8 *FileName
+)
+{
+ FILE *BinaryFd;
+ UINTN BytesWrite;
+ UINT32 SectionSize;
+
+ BinaryFd = NULL;
+ //
+ // Create the raw section files in FFS
+ //
+ BinaryFd = fopen (FileName, "wb+");
+ if (BinaryFd == NULL) {
+ printf ("Error. Failed to create the raw data section.\n");
+ return 0;
+ }
+ fseek (BinaryFd, 0, SEEK_SET);
+ BytesWrite = fwrite (Buffer, sizeof (CHAR8), Size, BinaryFd);
+ fclose (BinaryFd);
+ if (BytesWrite != Size) {
+ printf ("Error. Failed to write the raw data section.\n");
+ return 0;
+ }
+ CreateRawSection (FileName, FileName);
+
+ BinaryFd = fopen (FileName, "rb");
+ if (BinaryFd == NULL) {
+ printf ("Error. Failed to open the raw data section.\n");
+ return 0;
+ }
+ fseek (BinaryFd, 0, SEEK_SET);
+ BytesWrite = fread (Buffer, sizeof (CHAR8), (Size + sizeof (EFI_COMMON_SECTION_HEADER)), BinaryFd);
+ fclose (BinaryFd);
+ if (BytesWrite != (Size + sizeof (EFI_COMMON_SECTION_HEADER))) {
+ printf ("Error. Failed to read the raw data section.\n");
+ return 0;
+ }
+
+ SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)Buffer)->Size);
+ return SectionSize;
+}
+
+/**
+ Read NvStoreDataBase and insert it to the Storage list.
+
+ @param InputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+ReadStorageFromNvStoreDatabase (
+ IN LIST_ENTRY *VarListEntry
+)
+{
+
+ UINT8 *Binary;
+ UINT8 *FullBinary;
+ UINT8 *VarDataBinary;
+ UINT8 *PreVarDataBinary;
+ UINT8 *DataBase;
+ PCD_DEFAULT_DATA *DeltaVarStoreHeader;
+ PCD_DEFAULT_DATA *PrePcdDefaultData;
+ UINT8 *DeltaData;
+ UINT32 DeltaSize;
+ UINT32 DataSize;
+ UINT32 HeaderSize;
+ UINT32 BinaryLength;
+ UINT32 Size;
+ UINT32 PreVarDataSize;
+ PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
+ UINT32 Offset;
+ UINT32 Value;
+ UINT32 Index;
+
+ BinaryLength = 0;
+ Binary = NULL;
+ FullBinary = NULL;
+ DataBase = NULL;
+ DeltaVarStoreHeader = NULL;
+ PreVarDataBinary = NULL;
+ PreVarDataSize = 0;
+ DeltaSize = 0;
+ Size = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER);
+ VarDataBinary = NULL;
+
+ //
+ // Check whether the FD has included the storage FFS
+ //
+ //if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
+ // return EFI_ABORTED;
+ //}
+ NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)gEfiFdInfo.NvStoreDatabase;
+ BinaryLength = NvStoreHeader->Length;
+ Binary = (UINT8 *)gEfiFdInfo.NvStoreDatabase;
+ //
+ // If detect size optimized format, transfer it to normal format
+ // before parse it
+ //
+ if (mMultiPlatformParam.SizeOptimized) {
+ FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
+ if (FullBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ }
+ while (Size < BinaryLength) {
+ DataBase = Binary + Size;
+ DataSize = *(UINT32 *)DataBase;
+ if (Size == sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
+ PrePcdDefaultData = (PCD_DEFAULT_DATA *) DataBase;
+ HeaderSize = PrePcdDefaultData->HeaderSize;
+ PreVarDataSize = DataSize - 4 - HeaderSize;
+ VarDataBinary = malloc(DataSize);
+ if (VarDataBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (VarDataBinary, DataBase, DataSize);
+ PreVarDataBinary = malloc(DataSize - 4 - HeaderSize);
+ if (PreVarDataBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (PreVarDataBinary, DataBase + 4 + HeaderSize , DataSize - 4 - HeaderSize);
+ } else {
+ DeltaVarStoreHeader = (PCD_DEFAULT_DATA *)DataBase;
+ DeltaSize = DeltaVarStoreHeader->DataSize;
+ HeaderSize = DeltaVarStoreHeader->HeaderSize;
+ DeltaData = (UINT8*) DeltaVarStoreHeader;
+
+ VarDataBinary = malloc(PreVarDataSize + HeaderSize + 4);
+ if (VarDataBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ //
+ // Copy the default setting data
+ //
+ memcpy (VarDataBinary, DataBase, HeaderSize + 4);
+ memcpy (VarDataBinary + HeaderSize + 4, PreVarDataBinary, PreVarDataSize);
+ //
+ // Merge the delta data with default setting to get the full delta data
+ //
+ for (Index = 0; Index < (DeltaSize - HeaderSize - 4)/sizeof(PCD_DATA_DELTA); Index++) {
+ Offset = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Offset;
+ Value = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Value;
+ if (*(VarDataBinary + HeaderSize + 4 + Offset) != Value) {
+ *(VarDataBinary + HeaderSize + 4 + Offset) = (UINT8)Value;
+ }
+ }
+ }
+ //
+ // Store the Variable Data to VarListEntry
+ //
+
+ ReadNvStoreVariableToList(VarDataBinary, VarListEntry);
+ Size += (DataSize + 7) & ~7;
+ }
+
+ if (VarDataBinary != NULL) {
+ free (VarDataBinary);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read FFS from BFV and insert it to the Storage list.
+
+ @param InputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+ReadStorageFromBfv (
+ IN LIST_ENTRY *VarListEntry
+)
+{
+
+ UINT8 *Binary;
+ UINT8 *FullBinary;
+ UINT8 *DataBase;
+ UINT8 *PreVarStoreHeader;
+ DATA_DELTA *DeltaVarStoreHeader;
+ UINT8 *DeltaData;
+ UINT32 PreDataSize;
+ UINT32 DeltaSize;
+ UINT32 BinaryLength;
+ UINT32 Size;
+ UINT32 SectionSize;
+ UINT32 FullSectionLen;
+ UINT32 FullSectionSize;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINT16 Offset;
+ UINT8 Value;
+ UINT32 Index;
+ CHAR8 *SectionName;
+
+ BinaryLength = 0;
+ Binary = NULL;
+ FullBinary = NULL;
+ DataBase = NULL;
+ PreVarStoreHeader = NULL;
+ DeltaVarStoreHeader = NULL;
+ PreDataSize = 0;
+ DeltaSize = 0;
+ FullSectionSize = 0;
+ Size = sizeof (EFI_FFS_FILE_HEADER);
+ FfsHeader = NULL;
+ FullSectionLen = 0;
+ SectionName = NULL;
+
+ SectionName = getcwd(NULL, _MAX_PATH);
+ if (strlen (SectionName) + 2 * strlen (OS_SEP_STR) + strlen ("Temp") + strlen ("TempSection.sec") >
+ _MAX_PATH - 1) {
+ printf ("Error. The current path is too long.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ sprintf (SectionName + strlen (SectionName), "%cTemp%cTempSection.sec", OS_SEP, OS_SEP);
+ //
+ // Check whether the FD has included the storage FFS
+ //
+ if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
+ return EFI_ABORTED;
+ }
+ FfsHeader = (EFI_FFS_FILE_HEADER *)gEfiFdInfo.StorageFfsInBfv;
+ BinaryLength = FvBufExpand3ByteSize (FfsHeader->Size);
+ Binary = (UINT8 *)FfsHeader;
+ //
+ // If detect size optimized format, transfer it to normal format
+ // before parse it
+ //
+ if (mMultiPlatformParam.SizeOptimized) {
+ FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
+ if (FullBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ while (Size < BinaryLength) {
+ SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)(Binary + Size))->Size);
+ DataBase = Binary + Size + sizeof (EFI_COMMON_SECTION_HEADER);
+ if (Size == sizeof (EFI_FFS_FILE_HEADER)) {
+ PreVarStoreHeader = DataBase + *(UINT16 *)DataBase;
+ PreDataSize = SectionSize - (*(UINT16 *)DataBase + sizeof(EFI_COMMON_SECTION_HEADER));
+ memcpy (FullBinary, DataBase, SectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
+ FullSectionLen = CreateStorageSection (FullBinary, *(UINT16 *)DataBase + PreDataSize, SectionName);
+ } else {
+ DeltaVarStoreHeader = (DATA_DELTA *)(DataBase + *(UINT16 *)DataBase);
+ DeltaSize = *(UINT16 *)DataBase + PreDataSize;
+ DeltaData = FullBinary + FullSectionSize + *(UINT16 *)DataBase;
+ //
+ // Copy the DefaultId and PlatformId directly
+ //
+ memcpy (FullBinary + FullSectionSize, DataBase, *(UINT16 *)DataBase);
+ //
+ // Copy the default setting data
+ //
+ memcpy (DeltaData, PreVarStoreHeader, PreDataSize);
+ //
+ // Merge the delta data with default setting to get the full delta data
+ //
+ for (Index = 0; Index < (SectionSize - *(UINT16 *)DataBase - sizeof(EFI_COMMON_SECTION_HEADER))/sizeof(DATA_DELTA); Index++) {
+ Offset = (DeltaVarStoreHeader + Index)->Offset;
+ Value = (DeltaVarStoreHeader + Index)->Value;
+ if (*(DeltaData + Offset) != Value) {
+ *(DeltaData + Offset) = Value;
+ }
+ }
+ FullSectionLen = CreateStorageSection (FullBinary + FullSectionSize, DeltaSize, SectionName);
+ }
+ //
+ // Store the previous binary information
+ //
+ DataBase = FullBinary + FullSectionSize + sizeof (EFI_COMMON_SECTION_HEADER);
+ PreVarStoreHeader = DataBase + *(UINT16 *)DataBase;
+
+ Size += (SectionSize + 3) & ~3;
+ FullSectionSize += (FullSectionLen + 3) & ~3;;
+ }
+ //
+ // Update to the new size
+ //
+ BinaryLength = FullSectionSize;
+ Binary = FullBinary;
+ Size = 0;
+ }
+
+ //
+ // Read the storage from BFV and insert to storage list
+ //
+ while (Size < BinaryLength) {
+ SectionSize = ReadStorageFromBinary ((Binary + Size), VarListEntry);
+ Size += (SectionSize + 3) & ~3;
+ }
+ if (FullBinary != NULL) {
+ free (FullBinary);
+ }
+
+ return EFI_SUCCESS;
+}
+
+#define SIZE_64K 0x10000
+
+/**
+ Create the storage and insert it to BFV by calling BfmLib.
+
+ @param InputFdName The pointer to the input fd name.
+ @param OutputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertBinaryToBfv (
+ IN CHAR8 *InputFdName,
+ IN CHAR8 *OutputFdName,
+ IN LIST_ENTRY *VarListEntry
+)
+{
+ UINT8 *Binary;
+ UINT8 *PreBinary;
+ UINT32 BinaryLength;
+ UINT32 PreBinaryLength;
+ UINT32 OptimizedBinaryLength;
+ UINT32 Size;
+ UINT32 OptimizedSize;
+ EFI_STATUS Status;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SectionNameFormatString;
+ CHAR8 *SystemCommand;
+ CHAR8 *TempSystemCommand;
+ INT32 ReturnValue;
+ CHAR8 *FileName;
+ BOOLEAN SizeOptimizedFlag;
+ CHAR8 *SectionName[_MAXIMUM_SECTION_FILE_NUM];
+ UINT32 Index;
+ CHAR8 *TemDir;
+ //
+ // Workaround for static code checkers.
+ // Ensures the size of 'IndexStr' can hold all the digits of an unsigned
+ // 32-bit integer.
+ //
+ CHAR8 IndexStr[16];
+
+ BinaryLength = 0;
+ PreBinaryLength = 0;
+ Storage = NULL;
+ StorageLink = NULL;
+ Binary = NULL;
+ PreBinary = NULL;
+ Size = 0;
+ OptimizedSize = 0;
+ Status = EFI_SUCCESS;
+ SystemCommandFormatString = NULL;
+ SectionNameFormatString = NULL;
+ SystemCommand = NULL;
+ TempSystemCommand = NULL;
+ SizeOptimizedFlag = FALSE;
+ Index = 0;
+ FileName = NULL;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ SectionNameFormatString = "%s%cTemp%c%s.sec";
+
+ memset (SectionName, 0, _MAXIMUM_SECTION_FILE_NUM * sizeof(CHAR8 *));
+ FileName = malloc (strlen (TemDir) + 1 + strlen ("Storage.ffs") + 1);
+ if (FileName == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (FileName, "%s%cStorage.ffs", TemDir, OS_SEP);
+ //
+ // Allocate the buffer which is the same with the input FD
+ //
+ Binary = malloc (SIZE_64K);
+ if (Binary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ PreBinary = malloc (SIZE_64K);
+ if (PreBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // If already existed a Storage.ffs in FD, keep the same format when execute update operation whatever input -a or not -a options.
+ //
+ if (mMultiPlatformParam.SizeOptimized
+ || (!mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam)
+ ) {
+ SizeOptimizedFlag = TRUE;
+ } else if (mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam && !mMultiPlatformParam.SizeOptimized) {
+ printf ("\nWarning. The \"-a\" parameter is ignored.\n");
+ }
+ //
+ // Build the binary for BFV
+ //
+ StorageLink = GetFirstNode (VarListEntry);
+
+ while (!IsNull (VarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (!Storage->Skip) {
+ //
+ // Assign the section name under the Temp directory
+ //
+ sprintf (IndexStr, "%d", Index);
+ SectionName[Index] = calloc (
+ strlen (SectionNameFormatString) + strlen (TemDir) + strlen(IndexStr) + 1,
+ sizeof(CHAR8)
+ );
+ if (SectionName[Index] == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SectionName[Index],
+ "%s%cTemp%c%s.sec",
+ TemDir,
+ OS_SEP,
+ OS_SEP,
+ IndexStr
+ );
+ memset(Binary, 0, SIZE_64K);
+ Size = PutStorageToBinary (Storage, Binary, VarListEntry);
+ assert (Size < SIZE_64K);
+ //
+ // Re-calculate the storage section by size optimization
+ //
+ if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+ OptimizedSize = OptimizeStorageSection (
+ PreBinary + sizeof (EFI_COMMON_SECTION_HEADER),
+ Binary,
+ PreBinary + PreBinaryLength,
+ Size
+ );
+ if (OptimizedSize == 0) {
+ printf ("Error. Failed to optimize the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+ //
+ // Create the raw section with normal format
+ //
+ assert (Size < SIZE_64K - sizeof (EFI_COMMON_SECTION_HEADER));
+ BinaryLength = CreateStorageSection (Binary, Size, SectionName[Index]);
+ if (BinaryLength == 0) {
+ printf ("Error. Failed to create the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ assert (BinaryLength < SIZE_64K);
+
+ //
+ // Create the raw section with optimized format
+ //
+ if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+ OptimizedBinaryLength = CreateStorageSection (PreBinary + PreBinaryLength, OptimizedSize, SectionName[Index]);
+ if (OptimizedBinaryLength == 0) {
+ printf ("Error. Failed to create the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+ PreBinaryLength = BinaryLength;
+ memcpy (PreBinary, Binary, PreBinaryLength);
+ Index++;
+ }
+ StorageLink = GetNextNode (VarListEntry, StorageLink);
+ }
+ //
+ // Create the raw ffs by GenFfs
+ //
+ CreateRawFfs (&SectionName[0], FileName, SizeOptimizedFlag);
+
+ //
+ // Call BfmLib to insert this binary into the BFV of FD.
+ //
+ //
+ // Construction 'system' command string
+ //
+ if (mMultiPlatformParam.ExistStorageFfsInBfv) {
+ if (mFvNameGuidString != NULL) {
+ SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\" -g %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -r \"%s\" \"%s\" \"%s\" -g %s",
+ mInputFdName,
+ FileName,
+ mOutputFdName,
+ mFvNameGuidString
+ );
+ } else {
+ SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -r \"%s\" \"%s\" \"%s\"",
+ mInputFdName,
+ FileName,
+ mOutputFdName
+ );
+ }
+ } else {
+ if (mFvNameGuidString != NULL) {
+ SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\" -g %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -i \"%s\" \"%s\" \"%s\" -g %s",
+ mInputFdName,
+ FileName,
+ mOutputFdName,
+ mFvNameGuidString
+ );
+ } else {
+ SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -i \"%s\" \"%s\" \"%s\"",
+ mInputFdName,
+ FileName,
+ mOutputFdName
+ );
+ }
+ }
+
+ if (mFullGuidToolDefinitionDir[0] != 0) {
+ TempSystemCommand = SystemCommand;
+ SystemCommand = malloc (
+ strlen (mFullGuidToolDefinitionDir) + strlen ("\\") + strlen (TempSystemCommand ) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ free (TempSystemCommand);
+ goto Done;
+ }
+ strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+ strcat (SystemCommand, OS_SEP_STR);
+ strcat (SystemCommand, TempSystemCommand);
+ free (TempSystemCommand);
+ }
+
+ ReturnValue = system (SystemCommand);
+ free (SystemCommand);
+ remove (FileName);
+ if (ReturnValue == -1) {
+ Status = EFI_ABORTED;
+ }
+Done:
+ for (Index = 0; SectionName[Index] != NULL; Index++) {
+ free (SectionName[Index]);
+ }
+ if (PreBinary != NULL) {
+ free (PreBinary);
+ }
+ if (Binary) {
+ free (Binary);
+ }
+ return Status;
+}
+
+/**
+ Create the storage and insert it to NvStoreDatabase.
+
+ @param InputFdName The pointer to the input fd name.
+ @param OutputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertBinaryToNvStoreDatabase (
+ IN CHAR8 *InputFdName,
+ IN CHAR8 *OutputFdName,
+ IN LIST_ENTRY *VarListEntry
+)
+{
+ UINT8 *Binary;
+ UINT8 *PreBinary;
+ UINT8 *NvStoreDatabaseBuffer;
+ UINT32 PreBinaryLength;
+ UINT32 Size;
+ UINT32 NvStoreDatabaseSize;
+ UINT32 OptimizedSize;
+ EFI_STATUS Status;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN SizeOptimizedFlag;
+ PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreBufferHeader;
+ PCD_DEFAULT_DATA *PcdDefaultData;
+
+ //
+ // Workaround for static code checkers.
+ // Ensures the size of 'IndexStr' can hold all the digits of an unsigned
+ // 32-bit integer.
+ //
+
+ PreBinaryLength = 0;
+ Storage = NULL;
+ StorageLink = NULL;
+ Binary = NULL;
+ PreBinary = NULL;
+ NvStoreDatabaseBuffer = NULL;
+ PcdDefaultData = NULL;
+ Size = 0;
+ NvStoreDatabaseSize = 0;
+ OptimizedSize = 0;
+ Status = EFI_SUCCESS;
+ SizeOptimizedFlag = FALSE;
+
+ //
+ // Allocate the buffer which is the same with the input FD
+ //
+
+ Binary = malloc (SIZE_64K);
+ if (Binary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ NvStoreBufferHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *) gEfiFdInfo.NvStoreDatabase;
+ NvStoreDatabaseBuffer = malloc (NvStoreBufferHeader->MaxLength);
+ if (NvStoreDatabaseBuffer == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ memcpy(NvStoreDatabaseBuffer, gEfiFdInfo.NvStoreDatabase, NvStoreBufferHeader->MaxLength);
+ PreBinary = malloc (SIZE_64K);
+ if (PreBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ SizeOptimizedFlag = TRUE;
+ } else {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Build the binary for BFV
+ //
+ StorageLink = GetFirstNode (VarListEntry);
+ while (!IsNull (VarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (!Storage->Skip) {
+ memset(Binary, 0, SIZE_64K);
+ Size = PutStorageToNvStoreBinary (Storage, Binary, VarListEntry);
+ assert (Size < SIZE_64K);
+ //
+ // Re-calculate the storage section by size optimization
+ //
+ if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+ OptimizedSize = OptimizeStorageDeltaData (
+ PreBinary,
+ Binary,
+ NvStoreDatabaseBuffer + NvStoreDatabaseSize,
+ Size
+ );
+ if (OptimizedSize == 0) {
+ printf ("Error. Failed to optimize the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //Alignment
+ OptimizedSize = (OptimizedSize + 7) & ~7;
+ NvStoreDatabaseSize += OptimizedSize;
+ } else {
+ //Alignment
+ Size = (Size + 7) & ~7;
+ PcdDefaultData = (PCD_DEFAULT_DATA *)Binary;
+ memcpy(NvStoreDatabaseBuffer + sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER), Binary, Size + PcdDefaultData->HeaderSize + 4 );
+ PreBinaryLength = Size + PcdDefaultData->HeaderSize + 4;
+ NvStoreDatabaseSize = sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + PreBinaryLength;
+ memcpy(PreBinary, Binary, PreBinaryLength);
+ }
+ }
+ StorageLink = GetNextNode (VarListEntry, StorageLink);
+ }
+ if (NvStoreBufferHeader->Length != NvStoreDatabaseSize) {
+ ((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)NvStoreDatabaseBuffer)->Length = NvStoreDatabaseSize;
+ }
+ memcpy(gEfiFdInfo.NvStoreDatabase, NvStoreDatabaseBuffer, NvStoreDatabaseSize);
+
+Done:
+ DestroyAllStorage (&mAllVarListEntry);
+ if (PreBinary != NULL) {
+ free (PreBinary);
+ }
+ if (Binary) {
+ free (Binary);
+ }
+ return Status;
+}
+
+extern UINT32 mMaxCount;
+extern UINT32 mCount;
+extern CHAR8 *mStringBuffer;
+
+/**
+ Read the HII configure file from all FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ReadCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ UINT16 PreDefaultId;
+ UINT64 PrePlatformId;
+ LIST_ENTRY NewStorageListHead;
+ BOOLEAN BfvOverried;
+ FORMSET_STORAGE *Storage;
+ LIST_ENTRY *StorageLink;
+
+ Storage = NULL;
+ Status = EFI_SUCCESS;
+ BfvOverried = FALSE;
+ Index = 0;
+ PreDefaultId = 0xFFFF;
+ PrePlatformId = 0xFFFFFFFFFFFFFFFF;
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Read defaultId and platformId
+ //
+ if (!gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // If existed the variable data in BFV, abstract them to a variable list.
+ // If not exsited, just skip it.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadStorageFromNvStoreDatabase(&mBfvVarListEntry);
+ } else {
+ Status = ReadStorageFromBfv (&mBfvVarListEntry);
+ }
+ if (!EFI_ERROR (Status)) {
+ BfvOverried = TRUE;
+ }
+ }
+ //
+ // If not existed the storage data in BFV, evaluate the
+ // default value according to the defaultId and platformId
+ // Or else, skip it.
+ //
+ if (!BfvOverried) {
+ Status = EvaluateTheValueInFormset (FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Output the question and value information on screen
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Multi-platform mode support
+ //
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ StorageLink = GetFirstNode (&mBfvVarListEntry);
+ while (!IsNull (&mBfvVarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ continue;
+ } else {
+ PreDefaultId = Storage->DefaultId[0];
+ PrePlatformId = Storage->PlatformId[0];
+ }
+ InitializeListHead(&NewStorageListHead);
+ //
+ // Use the varaible stroage list from BFV
+ //
+ Status = BuildVariableList(
+ &NewStorageListHead,
+ &mBfvVarListEntry,
+ Storage->DefaultId[0],
+ Storage->PlatformId[0],
+ FALSE,
+ READ
+ );
+
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ if (IsListEmpty (&NewStorageListHead)) {
+ continue;
+ }
+ Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ DestroyAllStorage (&NewStorageListHead);
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ }
+ } else {
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ InitializeListHead(&NewStorageListHead);
+ if (BfvOverried) {
+ //
+ // Use the varaible stroage list from BFV
+ //
+ Status = BuildVariableList(
+ &NewStorageListHead,
+ &mBfvVarListEntry,
+ mMultiPlatformParam.DefaultId[DefaultIndex],
+ mMultiPlatformParam.PlatformId[PlatformIndex],
+ FALSE,
+ READ
+ );
+ } else {
+ //
+ // Use the varaible storage list from IFR
+ //
+ Status = BuildVariableList(
+ &NewStorageListHead,
+ &mAllVarListEntry,
+ mMultiPlatformParam.DefaultId[DefaultIndex],
+ mMultiPlatformParam.PlatformId[PlatformIndex],
+ FALSE,
+ READ
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ if (IsListEmpty (&NewStorageListHead)) {
+ continue;
+ }
+ Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ DestroyAllStorage (&NewStorageListHead);
+ }
+ }
+ }
+ } else {
+ Status = PrintInfoInAllFormset (&mFormSetListEntry, &mAllVarListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Update the HII setup value.
+
+ Read the Config information from config file, and then compare it with the current FFS.
+ Record the different value to EFI variable.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+UpdateCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ BOOLEAN BfvOverried;
+
+ Status = EFI_SUCCESS;
+ BfvOverried = FALSE;
+ Index = 0;
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Read defaultId and platformId
+ //
+ if (!gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // If existed the variable data in BFV, abstract them to a variable list.
+ // If not exsited, just skip it.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadStorageFromNvStoreDatabase (&mBfvVarListEntry);
+ } else {
+ Status = ReadStorageFromBfv (&mBfvVarListEntry);
+ }
+ if (!EFI_ERROR (Status)) {
+ BfvOverried = TRUE;
+ }
+ }
+ if (mMultiPlatformParam.MultiPlatformOrNot && BfvOverried) {
+ if (mUqiList == NULL) {
+ return EFI_SUCCESS;
+ }
+ Status = CheckValueUpdateList ();
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ } else {
+ //
+ // Evaluate the default value according to the defaultId and platformId
+ //
+ if (mUqiList == NULL) {
+ Status = EvaluateTheValueInFormset (FALSE);
+ } else {
+ Status = EvaluateTheValueInFormset (TRUE);
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // print error information in UQI list
+ //
+ if (PrintErrorInfo (mUqiList)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Output the variable information to BFV in multi-platform mode
+ // Or write it to the Nvstrage in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (ExistEfiVarOrNot (&mAllVarListEntry) && Operations == UPDATE) {
+ printf ("Error. Please use --remove or --ignore to update the variable storage for an FD with variables in its NvStorage.\n");
+ return EFI_ABORTED;
+ }
+ } else {
+ //
+ // Sync the data from List data to efi variable.
+ //
+ Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ printf ("Error. There is no available space in efi variable. \n");
+ return EFI_ABORTED;
+ }
+ if (Status == EFI_INVALID_PARAMETER) {
+ return EFI_ABORTED;
+ }
+ }
+
+ PrintUpdateListInfo (mUqiList);
+
+ return Status;
+}
+
+/**
+ Quick Update the HII setup value.
+
+ Read the Config information from command line directly, and then compare it with the current FFS.
+ Record the different value to EFI variable.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+
+EFI_STATUS
+QuickUpdateCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
+ return EFI_ABORTED;
+ }
+ //
+ // Check whether the FD has included the storage FFS
+ //
+ if (mMultiPlatformParam.ExistStorageFfsInBfv) {
+ printf ("Error. Variable storage exists in BFV of Fd. This is generated in multi-platform mode.\n");
+ printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
+ return EFI_ABORTED;
+ }
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Evaluate the default value according to the defaultId and platformId
+ //
+ Status = EvaluateTheValueInFormset (TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // print error information in UQI list
+ //
+ if (PrintErrorInfo (mUqiList)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Sync the data from mAllVarListEntry data to efi variable.
+ //
+ Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ printf ("Error. There is no available space in Nvstorage. \n");
+ return EFI_ABORTED;
+ }
+ if (Status == EFI_INVALID_PARAMETER) {
+ return EFI_ABORTED;
+ }
+
+ PrintUpdateListInfo (mUqiList);
+
+ return Status;
+}
+
+/**
+ Check the HII setup value.
+
+ Read the Config information from config file, and then compare it with the current FFS.
+ Print the different values on screen.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+CheckCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ UINT16 DefaultId;
+ UINT64 PlatformId;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+ DefaultIndex = 0;
+ PlatformIndex = 0;
+ DefaultId = 0;
+ PlatformId = 0;
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Read defaultId and platformId
+ //
+ Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Read the config data from BFV in multi-platform mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ Status = ReadStorageFromBfv (&mAllVarListEntry);
+ if (EFI_ERROR (Status)) {
+ printf ("Error. No storage variable data exists in BFV.\n");
+ return EFI_ABORTED;
+ }
+ }
+
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ ScanUqiFullList (mUqiList);
+
+ //
+ // Multi-platform mode support
+ //
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
+ PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+
+ InitializeListHead(&mVarListEntry);
+ Status = BuildVariableList(
+ &mVarListEntry,
+ &mAllVarListEntry,
+ DefaultId,
+ PlatformId,
+ FALSE,
+ VERIFY
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ if (IsListEmpty (&mVarListEntry)) {
+ continue;
+ }
+ SetUqiParametersMultiMode (mUqiList, DefaultId, PlatformId);
+ DestroyAllStorage (&mVarListEntry);
+ }
+ }
+ } else {
+ //
+ // General mode
+ //
+ Status = ExtractDefault (
+ NULL,
+ NULL,
+ 0,
+ 0,
+ SystemLevel
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // If existed the variable in NvStorage, copy them to mVarListEntry.
+ // Synchronize the default value from the EFI variable zone to variable list
+ //
+ Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
+ if (Status == EFI_INVALID_PARAMETER) {
+ Status = EFI_ABORTED;
+ return Status;
+ }
+ //
+ // Update the value from script file
+ //
+ Status = SetUqiParameters (mUqiList,0, 0);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, VERIFY);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ PrintVerifiedListInfo (mUqiList);
+ return Status;
+}
+
+/**
+ Search the config file from the path list.
+
+ Split the path from env PATH, and then search the cofig
+ file from these paths. The priority is from left to
+ right of PATH string. When met the first Config file, it
+ will break and return the pointer to the full file name.
+
+ @param PathList the pointer to the path list.
+ @param FileName the pointer to the file name.
+
+ @retval The pointer to the file name.
+ @return NULL An error occurred.
+**/
+CHAR8 *
+SearchConfigFromPathList (
+ IN CHAR8 *PathList,
+ IN CHAR8 *FileName
+)
+{
+ CHAR8 *CurDir;
+ CHAR8 *FileNamePath;
+
+ CurDir = NULL;
+ FileNamePath = NULL;
+#ifndef __GNUC__
+ CurDir = strtok (PathList,";");
+#else
+ CurDir = strtok (PathList,":");
+#endif
+ while (CurDir != NULL) {
+ FileNamePath = (char *)calloc(
+ strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
+ sizeof(char)
+ );
+ if (FileNamePath == NULL) {
+ return NULL;
+ }
+ sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
+ if (access (FileNamePath, 0) != -1) {
+ return FileNamePath;
+ }
+#ifndef __GNUC__
+ CurDir = strtok(NULL, ";");
+#else
+ CurDir = strtok(NULL, ":");
+#endif
+ free (FileNamePath);
+ FileNamePath = NULL;
+ }
+ return NULL;
+}
+
+/**
+ FCE application entry point
+
+ @param argc The number of input parameters.
+ @param *argv[] The array pointer to the parameters.
+
+ @retval 0 The application exited normally.
+ @retval 1 An error occurred.
+ @retval 2 An error about check occurred.
+
+**/
+int
+main (
+ int argc,
+ char *argv[]
+ )
+{
+ EFI_STATUS Status;
+ FILE *OutputFd;
+ FILE *ScriptFile;
+ UINTN BytesWrite;
+ UINTN Index;
+ CHAR8 *TemDir;
+ BOOLEAN IsFileExist;
+ CHAR8 FullGuidToolDefinition[_MAX_PATH];
+ CHAR8 *PathList;
+ UINTN EnvLen;
+ CHAR8 *NewPathList;
+ UINTN FileNameIndex;
+ CHAR8 *InFilePath;
+ BOOLEAN UqiIsSet;
+
+ Status = EFI_SUCCESS;
+ OutputFd = NULL;
+ ScriptFile = NULL;
+ Operations = NONE;
+ BytesWrite = 0;
+ Index = 0;
+ TemDir = NULL;
+ mFormSetOrderRead = 0;
+ mFormSetOrderParse = 0;
+ IsFileExist = TRUE;
+ PathList = NULL;
+ NewPathList = NULL;
+ EnvLen = 0;
+ UqiIsSet = FALSE;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return FAIL;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ memset (&mMultiPlatformParam, 0, sizeof (MULTI_PLATFORM_PARAMETERS));
+
+ SetUtilityName (UTILITY_NAME);
+ //
+ // Workaroud: the first call to this function
+ // returns a file name ends with dot
+ //
+#ifndef __GNUC__
+ tmpnam (NULL);
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ close(Fdtmp);
+#endif
+ //
+ // Save, and then skip filename arg
+ //
+ mUtilityFilename = argv[0];
+ argc--;
+ argv++;
+ //
+ // Get the same path with the application itself
+ //
+ if (strlen (mUtilityFilename) > _MAX_PATH - 1) {
+ Error (NULL, 0, 2000, "Parameter: The input file name is too long", NULL);
+ return FAIL;
+ }
+ strncpy (FullGuidToolDefinition, mUtilityFilename, _MAX_PATH - 1);
+ FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+ FileNameIndex = strlen (FullGuidToolDefinition);
+ while (FileNameIndex != 0) {
+ FileNameIndex --;
+ if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+ FullGuidToolDefinition[FileNameIndex] = 0;
+ strcpy (mFullGuidToolDefinitionDir, FullGuidToolDefinition);
+ break;
+ }
+ }
+ //
+ // Build the path list for Config file scan. The priority is below.
+ // 1. Scan the current path
+ // 2. Scan the same path with the application itself
+ // 3. Scan the current %PATH% of OS environment
+ // 4. Use the build-in default configuration
+ //
+ PathList = getenv("PATH");
+ if (PathList == NULL) {
+ Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
+ return FAIL;
+ }
+ EnvLen = strlen(PathList);
+ NewPathList = (char *)calloc(
+ strlen (".")
+ + strlen (";")
+ + strlen (mFullGuidToolDefinitionDir)
+ + strlen (";")
+ + EnvLen
+ + 1,
+ sizeof(char)
+ );
+ if (NewPathList == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ PathList = NULL;
+ free (PathList);
+ return -1;
+ }
+#ifndef __GNUC__
+ sprintf (NewPathList, "%s;%s;%s", ".", mFullGuidToolDefinitionDir, PathList);
+#else
+ sprintf (NewPathList, "%s:%s:%s", ".", mFullGuidToolDefinitionDir, PathList);
+#endif
+
+ PathList = NULL;
+ free (PathList);
+
+ //
+ // Load Guid Tools definition
+ //
+ InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
+ free (NewPathList);
+ if (InFilePath != NULL) {
+ printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath);
+ mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+ free (InFilePath);
+ } else {
+ //
+ // Use the pre-defined standard guided tools.
+ //
+ printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n");
+ mParsedGuidedSectionTools = PreDefinedGuidedTools ();
+ }
+ //
+ // Parse the command line
+ //
+ strcpy (mSetupTxtName, "NoSetupFile");
+ Status = ParseCommmadLine (argc,argv);
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Print utility header
+ //
+ printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
+ UTILITY_NAME,
+ UTILITY_MAJOR_VERSION,
+ UTILITY_MINOR_VERSION,
+ __BUILD_VERSION
+ );
+ //
+ // Check the revision of BfmLib
+ //
+ Status = CheckBfmLibRevision ();
+ if (EFI_ERROR (Status)) {
+ printf ("Please use the correct revision of BfmLib %s. \n", __BUILD_VERSION);
+ return FAIL;
+ }
+ if (strcmp (mSetupTxtName, "NoSetupFile")) {
+ ScriptFile = fopen (mSetupTxtName, "r");
+ if (ScriptFile == NULL) {
+ printf ("Error. Cannot open the script file.\n");
+ return FAIL;
+ }
+ Status = PickUpUqiFromScript (ScriptFile);
+ if (EFI_ERROR (Status)) {
+ fclose (ScriptFile);
+ IsFileExist = FALSE;
+ goto Done;
+ }
+ fclose (ScriptFile);
+ }
+ if (!mMultiPlatformParam.MultiPlatformOrNot
+ && (Operations == UPDATE_REMOVE || Operations == UPDATE_IGNORE)
+ ) {
+ printf ("Error. --remove and --ignore cannot be used in normal mode.\n");
+ Status = FAIL;
+ goto Done;
+ }
+
+ if (access (TemDir, 0) != -1) {
+ LibRmDir (TemDir);
+ }
+
+ //
+ // Initialize the variables
+ //
+ Status = PickUpFfsFromFd ();
+ if (EFI_ERROR (Status)) {
+ printf ("Error. Invalid FD file.\n");
+ IsFileExist = FALSE;
+ Status = FAIL;
+ goto Done;
+ }
+ if (gEfiFdInfo.FfsArray[0] == NULL) {
+ printf ("Error. Cannot find any HII offset in current FD files, please check the BaseTools.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ //
+ //Config the global variables
+ //
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ UqiIsSet = TRUE;
+ }
+ Status = GetEfiVariablesAddr (UqiIsSet);
+ if (EFI_ERROR (Status)) {
+ printf ("Error. Cannot locate the EFI variable zone in FD.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ if (gEfiFdInfo.ExistNvStoreDatabase && !mMultiPlatformParam.MultiPlatformOrNot) {
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ }
+ //
+ // Initialize the FormSet and VarList List
+ //
+ InitializeListHead (&mFormSetListEntry);
+ InitializeListHead (&mVarListEntry);
+ InitializeListHead (&mBfvVarListEntry);
+ InitializeListHead (&mAllVarListEntry);
+
+ mStringBuffer = malloc (mMaxCount);
+ if (mStringBuffer == NULL) {
+ printf ("Fali to allocate memory!\n");
+ Status = FAIL;
+ goto Done;
+ }
+
+ //
+ // Decide how to deal with the Fd
+ //
+ switch (Operations) {
+
+ case READ:
+ printf ("\nStart the Read Mode:\n");
+ Status = ReadCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = FAIL;
+ }
+ break;
+
+ case UPDATE:
+ case UPDATE_REMOVE:
+ case UPDATE_IGNORE:
+ printf ("\nStart the Update Mode:\n");
+ Status = UpdateCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = FAIL;
+ }
+ break;
+
+ case VERIFY:
+ printf ("\nStart the Verify Mode:\n");
+ Status = CheckCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = VR_FAIL;
+ }
+ break;
+
+ case UPDATEQ:
+ printf ("\nStart the Update Quick Mode:\n");
+ Status = QuickUpdateCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = FAIL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (mCount > 0) {
+ mStringBuffer[mCount] = '\0';
+ fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
+ }
+ free (mStringBuffer);
+
+ if (Status != SUCCESS) {
+ goto Done;
+ }
+ //
+ // If multi-platform mode, insert the variables to BFV
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot
+ && (IsListEmpty (&mAllVarListEntry) == FALSE)
+ &&((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ))
+ ) {
+ IsFileExist = FALSE;
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = InsertBinaryToNvStoreDatabase (mInputFdName, mOutputFdName, &mAllVarListEntry);
+ } else {
+ Status = InsertBinaryToBfv (mInputFdName, mOutputFdName, &mAllVarListEntry);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Remove the variables in NvStorage in multi-platform mode by user specified requirement
+ //
+ if (Operations == UPDATE_REMOVE) {
+ if (gEfiFdInfo.Fd != NULL) {
+ free (gEfiFdInfo.Fd);
+ }
+ gEfiFdInfo.Fd = ReadFileToMemory (mOutputFdName, &gEfiFdInfo.FdSize);
+ if (gEfiFdInfo.Fd == NULL) {
+ Status = EFI_ABORTED;
+ } else {
+ Status = RemoveEfiVar (&mAllVarListEntry);
+ }
+ if (EFI_ERROR (Status)) {
+ printf ("Error. Failed to remove the variable from NVRAM.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ }
+ }
+
+ if (
+ (!mMultiPlatformParam.MultiPlatformOrNot &&((Operations == UPDATE) || (Operations == UPDATEQ)))
+ || (mMultiPlatformParam.MultiPlatformOrNot && (Operations == UPDATE_REMOVE || ((Operations == UPDATE) && IsListEmpty (&mAllVarListEntry))))
+ ) {
+ OutputFd = fopen (mOutputFdName, "wb+");
+ if (OutputFd == NULL) {
+ printf ("Error. Failed to create the output FD file.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ fseek (OutputFd, 0, SEEK_SET);
+ BytesWrite = fwrite (gEfiFdInfo.Fd, sizeof (CHAR8), gEfiFdInfo.FdSize, OutputFd);
+ fclose (OutputFd);
+ if (BytesWrite != gEfiFdInfo.FdSize) {
+ printf ("Error. Failed to create the FD image. \n");
+ Status = FAIL;
+ goto Done;
+ }
+ }
+ if ((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ)) {
+ printf ("\nCongratulations. The output Fd file '%s' has been completed successfully.\n", mOutputFdName);
+ }
+Done:
+ //
+ // Delete the temporary directory and files
+ //
+ if (IsFileExist) {
+ LibRmDir (TemDir);
+ }
+ //
+ // Clean up
+ //
+ if (gEfiFdInfo.Fd != NULL) {
+ free (gEfiFdInfo.Fd);
+ }
+
+ if (mMultiPlatformParam.Uqi.Value != NULL) {
+ free (mMultiPlatformParam.Uqi.Value);
+ }
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ free (mMultiPlatformParam.Uqi.Data);
+ }
+ while (gEfiFdInfo.FfsArray[Index] != NULL) {
+ free (gEfiFdInfo.FfsArray[Index++]);
+ }
+
+ DestroyAllFormSet (&mFormSetListEntry);
+ DestroyAllStorage (&mVarListEntry);
+ DestroyAllStorage (&mBfvVarListEntry);
+ DestroyAllStorage (&mAllVarListEntry);
+ FreeUnidirectionList (mUqiList);
+
+ return Status;
+}
+
diff --git a/BaseTools/Source/C/FCE/IfrParse.c b/BaseTools/Source/C/FCE/IfrParse.c
new file mode 100644
index 0000000000..2f5a87baf3
--- /dev/null
+++ b/BaseTools/Source/C/FCE/IfrParse.c
@@ -0,0 +1,4836 @@
+/** @file
+
+ Parser for IFR binary encoding.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IfrParse.h"
+
+#ifndef EDKII_IFR_BIT_VARSTORE_GUID
+#define EDKII_IFR_BIT_VARSTORE_GUID \
+ {0x82DDD68B, 0x9163, 0x4187, {0x9B, 0x27, 0x20, 0xA8, 0xFD, 0x60 ,0xA7, 0x1D}}
+#endif
+
+#ifndef EDKII_IFR_NUMERIC_SIZE_BIT
+#define EDKII_IFR_NUMERIC_SIZE_BIT 0x3F
+#endif
+
+UINT16 mStatementIndex;
+UINT16 mExpressionOpCodeIndex;
+
+BOOLEAN mInScopeSubtitle;
+BOOLEAN mInScopeSuppress;
+BOOLEAN mInScopeGrayOut;
+BOOLEAN mInScopeDisable;
+FORM_EXPRESSION *mSuppressExpression;
+FORM_EXPRESSION *mGrayOutExpression;
+FORM_EXPRESSION *mDisableExpression;
+
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern LIST_ENTRY mVarListEntry;
+extern LIST_ENTRY mFormSetListEntry;
+extern UINT32 mFormSetOrderParse;
+
+#define FORM_SET_GUID_PREFIX "Form Set GUID: "
+#define EFI_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+
+UINT32 mMaxCount = 0x100000;
+UINT32 mCount = 0;
+CHAR8 *mStringBuffer = NULL;
+static EFI_GUID gEdkiiIfrBitVarGuid = EDKII_IFR_BIT_VARSTORE_GUID;
+
+/**
+ Produces a Null-terminated ASCII string in mStringBuffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ @param FormatString A null-terminated ASCII format string.
+ @param ... The variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+**/
+VOID
+StringPrint (
+ CHAR8 *FormatString,
+ ...
+)
+{
+ va_list Marker;
+ INT32 Count;
+
+ va_start (Marker, FormatString);
+ Count = vsprintf (mStringBuffer + mCount, FormatString, Marker);
+ mCount = mCount + Count;
+ va_end (Marker);
+ if (mCount + 0x400 > mMaxCount) {
+ mStringBuffer[mCount] = '\0';
+ fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
+ mCount = 0;
+ }
+}
+
+/**
+ Print the information of questions.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param Question The pointer to the question.
+ @param PrintOrNot Decide whether print or not.
+
+ @return NULL.
+
+**/
+static
+VOID
+PrintQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN BOOLEAN PrintOrNot
+ );
+
+/**
+ Writes a Unicode string specified by iStringToken and iLanguage to the script file (converted to ASCII).
+
+ @param Package A pointer to the Unicode string.
+
+ @return NULL
+
+**/
+static
+VOID
+LogUnicodeString (
+ IN CHAR16 *pcString
+ )
+{
+ UINTN Index;
+
+ if (pcString == NULL) {
+ return;
+ }
+ //
+ // replace the 0x0D to 0x20, because if the pcString has 0D 0A, then after print it,
+ // different editor may have different format
+ //
+ for (Index = 0; pcString[Index] != 0; Index++) {
+ if (pcString[Index] == 0x0D) {
+ pcString[Index] = 0x20;
+ }
+
+ StringPrint("%c", pcString[Index] & 0x00FF);
+ }
+}
+
+/**
+ Writes a UQIL Unicode string specified by iStringToken to the script file as an array of 16-bit integers in ASCII.
+
+ @param Package A pointer to the Unicode string.
+
+ @return NULL
+
+**/
+static
+VOID
+LogUqi (
+ IN CHAR16 *pcString
+ )
+{
+ UINT16 Index;
+ //
+ // Find the UNICODE string length (in CHAR16)
+ //
+ for (Index = 0; pcString[Index] != 0; Index++);
+ //
+ // Write each word as a hex integer
+ //
+ for (Index = 0; pcString[Index] != 0; Index++) {
+ StringPrint("%04X ", pcString[Index]);
+ }
+}
+
+/**
+ Get the question value with bit field from the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value get from.
+ @param Value Retun the value.
+
+**/
+VOID
+GetBitsQuestionValue(
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT8 *Buffer,
+ OUT UINT32 *Value
+ )
+{
+ UINT32 PreBits;
+ UINT32 Mask;
+
+ PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
+ Mask = (1<< Question->BitStorageWidth) -1;
+
+ *Value = *(UINT32*)Buffer;
+ (*Value) >>= PreBits;
+ (*Value) &= Mask;
+}
+
+/**
+ Set the question value with bit field to the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value set to.
+ @param Value The value need to set.
+
+**/
+VOID
+SetBitsQuestionValue (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN OUT UINT8 *Buffer,
+ IN UINT32 Value
+ )
+{
+ UINT32 PreBits;
+ UINT32 Mask;
+ UINT32 TmpValue;
+
+ PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
+ Value <<= PreBits;
+ Mask = (1<< Question->BitStorageWidth) -1;
+ Mask <<= PreBits;
+
+ TmpValue = *(UINT32*)(Buffer);
+ TmpValue = (TmpValue & (~Mask)) | Value;
+ CopyMem ((UINT32*)Buffer, &TmpValue, sizeof (UINT32));
+}
+
+/**
+ Print the current value of the specified question.
+
+ @param Question The pointer to question
+
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+ UINT32 Value;
+
+ VarBuffer = NULL;
+
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+
+ if (EFI_ERROR (Status)) {
+ StringPrint("\nCouldn't read current variable data.");
+ return EFI_ABORTED;
+ }
+ //
+ // Log the Value
+ //
+ if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->StorageWidth > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && !VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else {
+ if (Question->QuestionReferToBitField) {
+ GetBitsQuestionValue (Question, VarBuffer, &Value);
+ VarBuffer = (UINT8*)(&Value);
+ }
+ switch (Question->StorageWidth) {
+
+ case sizeof (UINT8):
+ StringPrint("%02X", (*(UINT8 *)VarBuffer) & 0xFF);
+ break;
+
+ case sizeof (UINT16):
+ StringPrint("%04X", (*(UINT16 *)VarBuffer) & 0xFFFF);
+ break;
+
+ case sizeof (UINT32):
+ StringPrint("%08X", (*(UINT32 *)VarBuffer) & 0xFFFFFFFF);
+ break;
+
+ case sizeof (UINT64):
+ StringPrint("%016llX", *((UINT64 *)VarBuffer));
+ break;
+
+ default:
+ StringPrint("0000 // Width > 16 is not supported -- FAILURE");
+ break;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the current value of the STRING question.
+
+ @param Question The pointer to question
+
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValueStr (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+
+ VarBuffer = NULL;
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+
+ if (EFI_ERROR (Status)) {
+ StringPrint("\nCouldn't read current variable data.");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Log the Value
+ //
+ if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->StorageWidth > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && !VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else {
+ StringPrint("\"");
+ LogUnicodeString((CHAR16 *)VarBuffer);
+ StringPrint("\"");
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the current values of an Ordered List question.
+
+ @param Question The pointer to question
+ @param MaxEntries The max number of options
+ @param VarList The dual pointer to the Node of VarList
+
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValueList (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 CurrentEntry;
+ UINT8 *VarBuffer;
+
+ CurrentEntry = 0;
+ VarBuffer = NULL;
+
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+
+ if (EFI_ERROR (Status)) {
+ StringPrint("\nCouldn't read current variable data.");
+ return EFI_ABORTED;
+ }
+ //
+ // Log the value
+ //
+ if (
+ ((Question->VarStoreInfo.VarOffset + Question->MaxContainers) > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->MaxContainers > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else {
+ for (CurrentEntry = 0; CurrentEntry < Question->MaxContainers; CurrentEntry++) {
+
+ switch (Question->StorageWidth/Question->MaxContainers){
+
+ case 1:
+ StringPrint("%02X ", VarBuffer[CurrentEntry]);
+ break;
+
+ case 2:
+ StringPrint("%04X ", *((UINT16 *)VarBuffer + CurrentEntry));
+ break;
+
+ case 4:
+ StringPrint("%08X ", *((UINT32 *)VarBuffer + CurrentEntry));
+ break;
+
+ case 8:
+ StringPrint("%016llX ", *((UINT64 *)VarBuffer + CurrentEntry));
+ break;
+
+ default:
+ StringPrint("%02X ", VarBuffer[CurrentEntry]);
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Compare two Uqi parameters
+
+ @param UqiParm1 The pointer to the first Uqi parameter.
+ @param UqiParm2 The pointer to the second Uqi parameter.
+
+ @retval TRUE If these two Uqi parameters are the same, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+BOOLEAN
+CompareUqiHeader (
+ IN CONST UQI_HEADER *UqiParm1,
+ IN CONST UQI_HEADER *UqiParm2
+ )
+{
+ INT32 Index;
+
+ if (UqiParm1->HexNum != UqiParm2->HexNum) {
+ return FALSE;
+ }
+
+ for (Index = UqiParm1->HexNum - 1; Index >= 0; Index--) {
+ if (UqiParm1->Data[Index] != UqiParm2->Data[Index]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Check whether existed a same variable in the LIST_ENTRY.
+
+ @param CurVarList A pointer to a variable node.
+
+ @return Pointer If existed the same variable, return the pointer to the Node.
+ @return NULL Otherwise, return FALSE
+
+**/
+static
+FORMSET_STORAGE *
+NotSameVariableInVarList (
+ IN LIST_ENTRY *VariableListEntry,
+ IN FORMSET_STORAGE *StorageNode
+ )
+{
+ FORMSET_STORAGE *CurNode;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *StorageListHead;
+
+ StorageListHead = VariableListEntry;
+ CurNode = NULL;
+
+ //
+ // Find Storage for this Question
+ //
+ Link = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, Link)) {
+ CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if (!CompareGuid (&StorageNode->Guid, &CurNode->Guid) \
+ && (CurNode->Name != NULL) \
+ && (StorageNode->Name != NULL) \
+ && !FceStrCmp (StorageNode->Name, CurNode->Name) \
+ && (StorageNode - CurNode != 0)
+ ) {
+ //
+ // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+ // two variables with same guid same name, but different type, we will take as the same
+ // in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == StorageNode->Type)) {
+ //
+ // If matched, get the address of EFI_IFR_VARSTORE data.
+ //
+ return CurNode;
+ break;
+ } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ return CurNode;
+ break;
+ }
+ }
+ Link = GetNextNode (StorageListHead, Link);
+ }
+ return NULL;
+}
+
+/**
+ Get the UniString by the offset.
+
+ @param UniPackge A pointer to the beginning of Null-terminated Unicode string Array.
+ @param CurUniPackge A pointer to the current position of Null-terminated Unicode string Array.
+ @param VarDefaultNameId The string ID.
+ @param CurOrDefaultLang Use the current language or the default language.
+ @param VarDefaultName return the name string.
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER
+ @return EFI_NOT_FOUND
+**/
+static
+EFI_STATUS
+GetStringByOffset (
+ IN UINT8 *UniPackge,
+ IN UINT8 *CurUniPackge,
+ IN UINT16 VarDefaultNameId,
+ IN BOOLEAN CurOrDefaultLang,
+ IN OUT CHAR16 **VarDefaultName
+ )
+{
+ UINT8 *HiiStringHeader;
+ UINT32 Offset;
+ UINT32 Count;
+ UINT32 Index;
+ EFI_HII_STRING_BLOCK *Block;
+ VOID *ThisBlock;
+
+ assert ((UniPackge != NULL) && (CurUniPackge != NULL));
+
+ HiiStringHeader = NULL;
+ Offset = 1;
+ Count = 0;
+ Block = NULL;
+ ThisBlock = NULL;
+
+ if (VarDefaultNameId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (CurOrDefaultLang) {
+ HiiStringHeader = CurUniPackge;
+ } else {
+ HiiStringHeader = UniPackge + 4;
+ }
+
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)HiiStringHeader + ((EFI_HII_STRING_PACKAGE_HDR *)HiiStringHeader)->HdrSize);
+ //
+ // Search the matched String in specificated language package by the Offset
+ //
+ while( Block->BlockType != EFI_HII_SIBT_END ) {
+ switch (Block->BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index + 1];
+ break;
+
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)(((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock) + 1);
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ ThisBlock = (VOID *)Block;
+ for( Count= ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
+ for ( ; ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ }
+ Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ ThisBlock = (VOID *)Block;
+ for( Count = ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) ;
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ ThisBlock = (VOID *)Block;
+ if (Offset == VarDefaultNameId) {
+ *VarDefaultName = malloc ((FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16));
+ if (*VarDefaultName == NULL) {
+ printf ("Fail to allocate memory");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ *VarDefaultName,
+ 0,
+ (FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16)
+ );
+ StrCpy (
+ *VarDefaultName,
+ (CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText
+ );
+ return EFI_SUCCESS;
+ }
+
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText[Index + 1];
+ Offset += 1;
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index + 1];
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ ThisBlock = (VOID *)Block;
+ for( Count = ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
+ for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ }
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ ThisBlock = (VOID *)Block;
+ for( Count= ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringCount, Index = 0 ; Count ; Count--, Index++ ) {
+ for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ }
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *)ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_DUPLICATE:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_DUPLICATE_BLOCK *) ThisBlock + 1);
+ break;
+
+ case EFI_HII_SIBT_SKIP2:
+ ThisBlock = (VOID *)Block;
+ Offset += ((EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock)->SkipCount;
+ Block = (EFI_HII_STRING_BLOCK *)( (EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock + 1);
+ break;
+
+ case EFI_HII_SIBT_SKIP1:
+ ThisBlock = (VOID *)Block;
+ Offset += ((EFI_HII_SIBT_SKIP1_BLOCK *) ThisBlock)->SkipCount;
+ Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_SKIP1_BLOCK *)ThisBlock + 1);
+ break;
+
+ case EFI_HII_SIBT_EXT1:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT1_BLOCK *) ThisBlock)->Length);
+ break;
+
+ case EFI_HII_SIBT_EXT2:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT2_BLOCK *) ThisBlock)->Length);
+ break;
+
+ case EFI_HII_SIBT_EXT4:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT4_BLOCK *)ThisBlock)->Length);
+ break;
+
+ case EFI_HII_SIBT_FONT:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index + 1];
+ break;
+
+ default:
+ StringPrint("Unhandled type = 0x%x\n", Block->BlockType);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Parse the UniString to get the string information.
+
+ @param CachedStringList A pointer to cached string list
+ @param UniPackge A pointer to a Null-terminated Unicode string Array.
+ @param VarDefaultNameId The string ID.
+ @param Language The language, en-US UQI or eng.
+ @param VarDefaultName return the name string.
+
+ @return EFI_SUCCESS If get the name string successfully
+ @return EFI_NOT_FOUND An error occurred.
+ @return EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+FindDefaultName (
+ IN FORMSET_STRING_LIST *CachedStringList,
+ IN UINT8 *UniPackge,
+ IN UINT16 VarDefaultNameId,
+ IN LANGUAGE Language,
+ IN OUT CHAR16 **VarDefaultName
+ )
+{
+ CHAR8 *UniPackgeEnd;
+ CHAR8 *UniBin;
+ CHAR8 LangStr[10];
+ BOOLEAN IsFound;
+ EFI_STATUS Status;
+ EFI_STRING_ID Index;
+ STRING_INFO *TempBuffer;
+
+ UniBin = NULL;
+ IsFound = FALSE;
+ Status = EFI_NOT_FOUND;
+
+ UniBin = (CHAR8 *) UniPackge + 4;
+ UniPackgeEnd = (CHAR8 *) UniPackge + *(UINT32 *)UniPackge;
+
+ //
+ //Handle with the invalid usage "STRING_TOKEN(0)"
+ //
+ if (VarDefaultNameId == 0) {
+ *VarDefaultName = L"";
+ return EFI_SUCCESS;
+ }
+
+ if (CachedStringList != NULL) {
+ for (Index = 0; Index < CachedStringList->CachedIdNum; Index ++) {
+ if (VarDefaultNameId == CachedStringList->StringInfoList[Index].StringId) {
+ *VarDefaultName = CachedStringList->StringInfoList[Index].String;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ switch (Language) {
+
+ case UQI:
+ strcpy (LangStr, "uqi");
+ break;
+
+ case EN_US:
+ strcpy (LangStr, "en-US");
+ break;
+
+ case ENG:
+ strcpy (LangStr, "eng");
+ break;
+
+ default:
+ strcpy (LangStr, "en-US");
+ break;
+ }
+ IsFound = FALSE;
+
+ if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ //
+ // Search the specified language package
+ //
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, LangStr) == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ //
+ //If not find the string ID, use the en eng or en-US instead.
+ //
+ if (!IsFound) {
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if ((strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0) \
+ || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) \
+ || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0) \
+ ) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ }
+ //
+ //If not still find the string ID, use the first one instead.
+ //
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ //If not find the specified string in UQI package, we use the en en-us eng or uqi insteadly
+ //
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ *VarDefaultName = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ if (CachedStringList != NULL) {
+ if (CachedStringList->CachedIdNum >= CachedStringList->MaxIdNum) {
+ TempBuffer = calloc (sizeof (STRING_INFO), CachedStringList->MaxIdNum + STRING_NUMBER);
+ if (TempBuffer == NULL) {
+ printf ("Fail to allocate memory! \n");
+ free (*VarDefaultName);
+ *VarDefaultName = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (TempBuffer, CachedStringList->StringInfoList, sizeof (STRING_INFO) * CachedStringList->MaxIdNum);
+ FreePool (CachedStringList->StringInfoList);
+ CachedStringList->StringInfoList = TempBuffer;
+ CachedStringList->MaxIdNum = CachedStringList->MaxIdNum + STRING_NUMBER;
+ }
+ CachedStringList->StringInfoList[CachedStringList->CachedIdNum].StringId = VarDefaultNameId;
+ CachedStringList->StringInfoList[CachedStringList->CachedIdNum].String = *VarDefaultName;
+ CachedStringList->CachedIdNum ++;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the variable Guid and Name by the variableId and FormSetOrder.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param ListEntry The pointer to the LIST_ENTRY.
+
+ @return EFI_SUCCESS
+ @return EFI_NOT_FOUND If not find the the variable, or the variable doesn't belong to EfiVarStore or VarStore.
+**/
+static
+EFI_STATUS
+GetGuidNameByVariableId (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN LIST_ENTRY *ListEntry
+ )
+{
+ FORMSET_STORAGE *CurNode;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *StorageListHead;
+ EFI_STATUS Status;
+ CHAR16 *EfiVariableName;
+
+ StorageListHead = ListEntry;
+ CurNode = NULL;
+ Status = EFI_SUCCESS;
+ EfiVariableName = NULL;
+
+ Link = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, Link)) {
+ CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if ((FormSet->FormSetOrder == CurNode->FormSetOrder) \
+ && (Question->VarStoreId == CurNode->VarStoreId)
+ ) {
+ //
+ // Copy type to question to avoid the case that EfiVarStore and VarStore have the same Guid and name.
+ //
+ Question->Type = CurNode->Type;
+ Question->NewEfiVarstore = CurNode->NewEfiVarstore;
+ Question->Attributes = CurNode->Attributes;
+
+ if (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP) {
+ CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
+ //
+ // If the first time to access the old EfiVarStore, need to sync the variable name
+ //
+ if (!CurNode->NewEfiVarstore) {
+ if (CurNode->Buffer == NULL) {
+ CurNode->Buffer = malloc (Question->StorageWidth);
+ }
+ if (CurNode->Name == NULL) {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->VarStoreInfo.VarName,
+ EN_US,
+ &EfiVariableName
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ CurNode->Name = EfiVariableName;
+ }
+ if (CurNode->Size == 0) {
+ CurNode->Size = Question->StorageWidth;
+ }
+ }
+ //
+ // Check whether the Efivariable variable name is valid.
+ //
+ if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
+ StringPrint ("Error. The variable name of question is NULL. Its UQI is: ");
+ StringPrint("Q %04X ", Question->Uqi.HexNum);
+ LogUqi (Question->Uqi.Data);
+ StringPrint ("\n");
+ return EFI_ABORTED;
+ }
+ if (Question->VariableName == NULL) {
+ Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
+ if (Question->VariableName == NULL) {
+ return EFI_ABORTED;
+ }
+ }
+ StrCpy (Question->VariableName, CurNode->Name);
+
+ return EFI_SUCCESS;
+
+ } else if (CurNode->Type == EFI_IFR_VARSTORE_OP) {
+ CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
+ if (Question->VariableName == NULL) {
+ Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
+ if (Question->VariableName == NULL) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Check whether the variable variable name is valid.
+ //
+ if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
+ StringPrint ("Error. The variable name of question is NULL. UQI:");
+ StringPrint("Q %04X ", Question->Uqi.HexNum);
+ LogUqi (Question->Uqi.Data);
+ StringPrint ("\n");
+ return EFI_ABORTED;
+ }
+ StrCpy (Question->VariableName, CurNode->Name);
+ return EFI_SUCCESS;
+ }
+ }
+ Link = GetNextNode (StorageListHead, Link);
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Search the variable list according to the variable Guid and name, and return the pointer
+ of that Node.
+
+ @param HiiObjList The pointer to the Question
+ @param VarName The EFI variable name need to be updated to VarList
+ @param Offset The offset of the variable
+ @param StorageListHead The pointer to the LIST_ENTRY of Storage
+ @param Vaue The value in that value offset of the variable
+ @param VarList The dual pointer of Varlist
+
+ @return EFI_SUCCESS
+ @return EFI_NOT_FOUND
+**/
+EFI_STATUS
+SearchVarStorage (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16* VarName,
+ IN UINT32 Offset,
+ IN LIST_ENTRY *StorageListHead,
+ IN OUT CHAR8 **Value,
+ IN OUT FORMSET_STORAGE **VarList
+ )
+{
+ FORMSET_STORAGE *CurNode;
+ LIST_ENTRY *Link;
+ BOOLEAN FindOrNot;
+
+ CurNode = NULL;
+ FindOrNot = FALSE;
+ *VarList = NULL;
+ //
+ // Find Storage for this Question
+ //
+ Link = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, Link)) {
+ CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+ //
+ // Deal with the old EfiVarstore before UEFI2.31
+ //
+ if (!CompareGuid (&Question->Guid, &CurNode->Guid) \
+ && (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && !CurNode->NewEfiVarstore \
+ && (Question->VariableName != NULL) \
+ && (CurNode->Name != NULL) \
+ && !FceStrCmp(Question->VariableName, CurNode->Name)
+ ) {
+ //
+ // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+ // two variables with same guid same name, but different type, we will take as the same
+ // in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
+ //
+ // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
+ //
+ *Value = (CHAR8 *)CurNode->Buffer;
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
+ //
+ *Value = (CHAR8 *)CurNode->Buffer;
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ }
+ }
+
+ if (!CompareGuid (&Question->Guid, &CurNode->Guid) \
+ && (CurNode->Name != NULL) \
+ && (Question->VariableName != NULL) \
+ && !FceStrCmp(Question->VariableName, CurNode->Name)
+ ) {
+ //
+ // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+ // two variables with same guid same name, but different type, we will take as the same
+ // in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
+ //
+ // If matched, get the address of EFI_IFR_VARSTORE data.
+ //
+ *Value = (CHAR8 *)(CurNode->Buffer + Offset);
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // If matched, get the address of EFI_IFR_VARSTORE data.
+ //
+ *Value = (CHAR8 *)(CurNode->Buffer + Offset);
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ }
+ }
+ Link = GetNextNode (StorageListHead, Link);
+ }
+ if (!FindOrNot) {
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN UINT8 *UniPackge
+ )
+{
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (UniPackge == NULL) {
+ return NULL;
+ }
+
+ Status = FindDefaultName (
+ NULL,
+ UniPackge,
+ Token,
+ EN_US,
+ &VarDefaultName
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return VarDefaultName;
+}
+
+/**
+ Initialize Statement header members.
+
+ @param OpCodeData Pointer of the raw OpCode data.
+ @param FormSet Pointer of the current FormSe.
+ @param Form Pointer of the current Form.
+
+ @return The Statement.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateStatement (
+ IN UINT8 *OpCodeData,
+ IN OUT FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ EFI_IFR_STATEMENT_HEADER *StatementHdr;
+
+ if (Form == NULL) {
+ //
+ // We are currently not in a Form Scope, so just skip this Statement
+ //
+ return NULL;
+ }
+
+ Statement = &FormSet->StatementBuffer[mStatementIndex];
+ mStatementIndex++;
+
+ InitializeListHead (&Statement->DefaultListHead);
+ InitializeListHead (&Statement->OptionListHead);
+ InitializeListHead (&Statement->InconsistentListHead);
+ InitializeListHead (&Statement->NoSubmitListHead);
+ InitializeListHead (&Statement->WarningListHead);
+
+ Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE;
+
+ Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+ Statement->QuestionReferToBitField = FALSE;
+
+ StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID));
+ CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID));
+
+ if (mInScopeSuppress) {
+ Statement->SuppressExpression = mSuppressExpression;
+ }
+
+ if (mInScopeGrayOut) {
+ Statement->GrayOutExpression = mGrayOutExpression;
+ }
+
+
+ if (mInScopeDisable) {
+ Statement->DisableExpression = mDisableExpression;
+ }
+
+ Statement->InSubtitle = mInScopeSubtitle;
+
+ //
+ // Insert this Statement into current Form
+ //
+ InsertTailList (&Form->StatementListHead, &Statement->Link);
+
+ return Statement;
+}
+
+/**
+ Initialize Question's members.
+
+ @param OpCodeData Pointer of the raw OpCode data.
+ @param FormSet Pointer of the current FormSet.
+ @param Form Pointer of the current Form.
+
+ @return The Question.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateQuestion (
+ IN UINT8 *OpCodeData,
+ IN OUT FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ EFI_IFR_QUESTION_HEADER *QuestionHdr;
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ NAME_VALUE_NODE *NameValueNode;
+
+ Statement = CreateStatement (OpCodeData, FormSet, Form);
+ if (Statement == NULL) {
+ return NULL;
+ }
+
+ QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID));
+ CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16));
+
+ Statement->QuestionFlags = QuestionHdr->Flags;
+
+ Statement->FormSetOrder = mFormSetOrderParse;
+
+ if (Statement->VarStoreId == 0) {
+ //
+ // VarStoreId of zero indicates no variable storage
+ //
+ return Statement;
+ }
+
+ //
+ // Find Storage for this Question
+ //
+ Link = GetFirstNode (FormSet->StorageListHead);
+ while (!IsNull (FormSet->StorageListHead, Link)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if ((Storage->VarStoreId == Statement->VarStoreId)
+ && (Storage->FormSetOrder == Statement->FormSetOrder)) {
+ Statement->Storage = Storage;
+ break;
+ }
+
+ Link = GetNextNode (FormSet->StorageListHead, Link);
+ }
+ ASSERT (Statement->Storage != NULL);
+
+ if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->UnicodeBinary);
+ ASSERT (Statement->VariableName != NULL);
+ //
+ // Insert to Name/Value varstore list
+ //
+ NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE));
+ ASSERT (NameValueNode != NULL);
+ NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE;
+ NameValueNode->Name = FceAllocateCopyPool (FceStrSize (Statement->VariableName), Statement->VariableName);
+ ASSERT (NameValueNode->Name != NULL);
+ NameValueNode->Value = AllocateZeroPool (0x10);
+ ASSERT (NameValueNode->Value != NULL);
+ NameValueNode->EditValue = AllocateZeroPool (0x10);
+ ASSERT (NameValueNode->EditValue != NULL);
+
+ InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link);
+ }
+
+ return Statement;
+}
+
+
+/**
+ Allocate a FORM_EXPRESSION node.
+
+ @param Form The Form associated with this Expression
+
+ @return Pointer to a FORM_EXPRESSION data structure.
+
+**/
+FORM_EXPRESSION *
+CreateExpression (
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_EXPRESSION *Expression;
+
+ Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+ ASSERT (Expression != NULL);
+ Expression->Signature = FORM_EXPRESSION_SIGNATURE;
+ InitializeListHead (&Expression->OpCodeListHead);
+
+ return Expression;
+}
+
+
+/**
+ Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List.
+
+ @param FormSet Pointer of the current FormSet
+
+ @return Pointer to a FORMSET_STORAGE data structure.
+
+**/
+FORMSET_STORAGE *
+CreateStorage (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ FORMSET_STORAGE *Storage;
+
+ Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE));
+ ASSERT (Storage != NULL);
+ Storage->Signature = FORMSET_STORAGE_SIGNATURE;
+ InitializeListHead (&Storage->NameValueListHead);
+ InsertTailList (FormSet->StorageListHead, &Storage->Link);
+
+ return Storage;
+}
+
+/**
+ Free resources of a Expression.
+
+ @param FormSet Pointer of the Expression
+
+**/
+VOID
+DestroyExpression (
+ IN FORM_EXPRESSION *Expression
+ )
+{
+ LIST_ENTRY *Link;
+ EXPRESSION_OPCODE *OpCode;
+ LIST_ENTRY *SubExpressionLink;
+ FORM_EXPRESSION *SubExpression;
+
+ while (!IsListEmpty (&Expression->OpCodeListHead)) {
+ Link = GetFirstNode (&Expression->OpCodeListHead);
+ OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+ RemoveEntryList (&OpCode->Link);
+
+ if (OpCode->ValueList != NULL) {
+ FreePool (OpCode->ValueList);
+ }
+
+ if (OpCode->ValueName != NULL) {
+ FreePool (OpCode->ValueName);
+ }
+
+ if (OpCode->MapExpressionList.ForwardLink != NULL) {
+ while (!IsListEmpty (&OpCode->MapExpressionList)) {
+ SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ RemoveEntryList(&SubExpression->Link);
+ DestroyExpression (SubExpression);
+ }
+ }
+ }
+
+ //
+ // Free this Expression
+ //
+ FreePool (Expression);
+}
+
+
+/**
+ Free resources of a storage.
+
+ @param Storage Pointer of the storage
+
+**/
+VOID
+DestroyStorage (
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *NameValueNode;
+
+ if (Storage == NULL) {
+ return;
+ }
+
+ if (Storage->Name != NULL) {
+ FreePool (Storage->Name);
+ }
+ if (Storage->Buffer != NULL) {
+ FreePool (Storage->Buffer);
+ }
+
+ while (!IsListEmpty (&Storage->NameValueListHead)) {
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link);
+ RemoveEntryList (&NameValueNode->Link);
+
+ if (NameValueNode->Name != NULL) {
+ FreePool (NameValueNode->Name);
+ }
+ if (NameValueNode->Value != NULL) {
+ FreePool (NameValueNode->Value);
+ }
+ if (NameValueNode->EditValue != NULL) {
+ FreePool (NameValueNode->EditValue);
+ }
+ FreePool (NameValueNode);
+ }
+
+ FreePool (Storage);
+ Storage = NULL;
+}
+
+/**
+ Free resources allocated for all Storage in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllStorage (
+ IN LIST_ENTRY *StorageEntryListHead
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ //
+ // Parse Fromset one by one
+ //
+ if (StorageEntryListHead->ForwardLink != NULL) {
+ while (!IsListEmpty (StorageEntryListHead)) {
+ Link = GetFirstNode (StorageEntryListHead);
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+ RemoveEntryList (&Storage->Link);
+
+ DestroyStorage (Storage);
+ }
+ }
+ StorageEntryListHead = NULL;
+}
+
+/**
+ Free resources of a Statement.
+
+ @param FormSet Pointer of the FormSet
+ @param Statement Pointer of the Statement
+
+**/
+VOID
+DestroyStatement (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_DEFAULT *Default;
+ QUESTION_OPTION *Option;
+ FORM_EXPRESSION *Expression;
+
+ //
+ // Free Default value List
+ //
+ while (!IsListEmpty (&Statement->DefaultListHead)) {
+ Link = GetFirstNode (&Statement->DefaultListHead);
+ Default = QUESTION_DEFAULT_FROM_LINK (Link);
+ RemoveEntryList (&Default->Link);
+
+ if (Default->Value.Buffer != NULL) {
+ FreePool(Default->Value.Buffer);
+ }
+ FreePool (Default);
+ }
+
+ //
+ // Free Options List
+ //
+ while (!IsListEmpty (&Statement->OptionListHead)) {
+ Link = GetFirstNode (&Statement->OptionListHead);
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ RemoveEntryList (&Option->Link);
+
+ FreePool (Option);
+ }
+
+ //
+ // Free Inconsistent List
+ //
+ while (!IsListEmpty (&Statement->InconsistentListHead)) {
+ Link = GetFirstNode (&Statement->InconsistentListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free NoSubmit List
+ //
+ while (!IsListEmpty (&Statement->NoSubmitListHead)) {
+ Link = GetFirstNode (&Statement->NoSubmitListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free WarningIf List
+ //
+ while (!IsListEmpty (&Statement->WarningListHead)) {
+ Link = GetFirstNode (&Statement->WarningListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+ if (Statement->VariableName != NULL) {
+ FreePool (Statement->VariableName);
+ }
+ if (Statement->BufferValue != NULL) {
+ FreePool (Statement->BufferValue);
+ }
+}
+
+/**
+ Free resources of a Form.
+
+ @param FormSet Pointer of the FormSet
+ @param Form Pointer of the Form.
+
+**/
+VOID
+DestroyForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ //
+ // Free Form Expressions
+ //
+ while (!IsListEmpty (&Form->ExpressionListHead)) {
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free Statements/Questions
+ //
+ while (!IsListEmpty (&Form->StatementListHead)) {
+ Link = GetFirstNode (&Form->StatementListHead);
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ RemoveEntryList (&Statement->Link);
+
+ DestroyStatement (FormSet, Statement);
+ }
+
+ //
+ // Free this Form
+ //
+ FreePool (Form);
+}
+
+
+/**
+ Free resources allocated for a FormSet.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ FORM_EXPRESSION *Expression;
+ FORM_BROWSER_FORM *Form;
+ UINT16 Index;
+
+ //
+ // Free FormSet Default Store
+ //
+ if (FormSet->DefaultStoreListHead.ForwardLink != NULL) {
+ while (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+ Link = GetFirstNode (&FormSet->DefaultStoreListHead);
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link);
+ RemoveEntryList (&DefaultStore->Link);
+
+ FreePool (DefaultStore);
+ }
+ }
+
+ //
+ // Free Formset Expressions
+ //
+ while (!IsListEmpty (&FormSet->ExpressionListHead)) {
+ Link = GetFirstNode (&FormSet->ExpressionListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free Forms
+ //
+ if (FormSet->FormListHead.ForwardLink != NULL) {
+ while (!IsListEmpty (&FormSet->FormListHead)) {
+ Link = GetFirstNode (&FormSet->FormListHead);
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ RemoveEntryList (&Form->Link);
+
+ DestroyForm (FormSet, Form);
+ }
+ }
+
+ if (FormSet->StatementBuffer != NULL) {
+ FreePool (FormSet->StatementBuffer);
+ }
+ if (FormSet->ExpressionBuffer != NULL) {
+ FreePool (FormSet->ExpressionBuffer);
+ }
+ if (FormSet->EnUsStringList.StringInfoList != NULL) {
+ for (Index = 0; Index < FormSet->EnUsStringList.CachedIdNum; Index ++) {
+ FreePool (FormSet->EnUsStringList.StringInfoList[Index].String);
+ }
+ FreePool (FormSet->EnUsStringList.StringInfoList);
+ }
+ if (FormSet->UqiStringList.StringInfoList != NULL) {
+ for (Index = 0; Index < FormSet->UqiStringList.CachedIdNum; Index ++) {
+ FreePool (FormSet->UqiStringList.StringInfoList[Index].String);
+ }
+ FreePool (FormSet->UqiStringList.StringInfoList);
+ }
+
+ FreePool (FormSet);
+}
+
+/**
+ Free resources allocated for all FormSet in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllFormSet (
+ IN LIST_ENTRY *FormSetEntryListHead
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *FormSet;
+ //
+ // Parse Fromset one by one
+ //
+ if (FormSetEntryListHead->ForwardLink != NULL) {
+ while (!IsListEmpty (FormSetEntryListHead)) {
+ Link = GetFirstNode (FormSetEntryListHead);
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ RemoveEntryList (&FormSet->Link);
+ DestroyFormSet (FormSet);
+ }
+ }
+}
+
+/**
+ Tell whether this Operand is an Expression OpCode or not
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Expression OpCode.
+ @retval FALSE Not an Expression OpCode.
+
+**/
+BOOLEAN
+IsExpressionOpCode (
+ IN UINT8 Operand
+ )
+{
+ if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) ||
+ ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SET_OP)) ||
+ ((Operand >= EFI_IFR_EQUAL_OP) && (Operand <= EFI_IFR_SPAN_OP)) ||
+ (Operand == EFI_IFR_CATENATE_OP) ||
+ (Operand == EFI_IFR_TO_LOWER_OP) ||
+ (Operand == EFI_IFR_TO_UPPER_OP) ||
+ (Operand == EFI_IFR_MAP_OP) ||
+ (Operand == EFI_IFR_VERSION_OP) ||
+ (Operand == EFI_IFR_SECURITY_OP)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/**
+ Calculate number of Statemens(Questions) and Expression OpCodes.
+
+ @param FormSet The FormSet to be counted.
+ @param NumberOfStatement Number of Statemens(Questions)
+ @param NumberOfExpression Number of Expression OpCodes
+
+**/
+VOID
+CountOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT UINT16 *NumberOfStatement,
+ IN OUT UINT16 *NumberOfExpression
+ )
+{
+ UINT16 StatementCount;
+ UINT16 ExpressionCount;
+ UINT8 *OpCodeData;
+ UINTN Offset;
+ UINTN OpCodeLen;
+
+ Offset = 0;
+ StatementCount = 0;
+ ExpressionCount = 0;
+
+ while (Offset < FormSet->IfrBinaryLength) {
+ OpCodeData = FormSet->IfrBinaryData + Offset;
+ OpCodeLen = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ Offset += OpCodeLen;
+
+ if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode)) {
+ ExpressionCount++;
+ } else {
+ StatementCount++;
+ }
+ }
+
+ *NumberOfStatement = StatementCount;
+ *NumberOfExpression = ExpressionCount;
+}
+
+
+
+/**
+ Parse opcodes in the formset IFR binary.
+
+ @param FormSet Pointer of the FormSet data structure.
+
+ @retval EFI_SUCCESS Opcode parse success.
+ @retval Other Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Index;
+ FORM_BROWSER_FORM *CurrentForm;
+ FORM_BROWSER_STATEMENT *CurrentStatement;
+ EXPRESSION_OPCODE *ExpressionOpCode;
+ FORM_EXPRESSION *CurrentExpression;
+ UINT8 Operand;
+ UINT8 Scope;
+ UINTN OpCodeOffset;
+ UINTN OpCodeLength;
+ UINT8 *OpCodeData;
+ UINT8 ScopeOpCode;
+ FORMSET_STORAGE *Storage;
+ FORMSET_STORAGE *TempStorage;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ QUESTION_DEFAULT *CurrentDefault;
+ QUESTION_OPTION *CurrentOption;
+ UINT8 Width;
+ CHAR8 *AsciiString;
+ UINT16 NumberOfStatement;
+ UINT16 NumberOfExpression;
+ BOOLEAN SuppressForQuestion;
+ BOOLEAN SuppressForOption;
+ BOOLEAN InScopeOptionSuppress;
+ FORM_EXPRESSION *OptionSuppressExpression;
+ BOOLEAN InScopeFormSuppress;
+ FORM_EXPRESSION *FormSuppressExpression;
+ UINT16 DepthOfDisable;
+ BOOLEAN OpCodeDisabled;
+ BOOLEAN SingleOpCodeExpression;
+ BOOLEAN InScopeDefault;
+ EFI_HII_VALUE *Value;
+ UINT8 MapScopeDepth;
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *VarStorage;
+ LIST_ENTRY *MapExpressionList;
+ EFI_VARSTORE_ID TempVarstoreId;
+ BOOLEAN ConstantFlag;
+ FORMSET_DEFAULTSTORE *PreDefaultStore;
+ LIST_ENTRY *DefaultLink;
+ BOOLEAN HaveInserted;
+ BOOLEAN BitFieldStorage;
+ UINT16 TotalBits;
+
+ mInScopeSubtitle = FALSE;
+ SuppressForQuestion = FALSE;
+ SuppressForOption = FALSE;
+ InScopeFormSuppress = FALSE;
+ mInScopeSuppress = FALSE;
+ InScopeOptionSuppress = FALSE;
+ mInScopeGrayOut = FALSE;
+ mInScopeDisable = FALSE;
+ DepthOfDisable = 0;
+ OpCodeDisabled = FALSE;
+ SingleOpCodeExpression = FALSE;
+ InScopeDefault = FALSE;
+ CurrentExpression = NULL;
+ CurrentDefault = NULL;
+ CurrentOption = NULL;
+ OptionSuppressExpression = NULL;
+ FormSuppressExpression = NULL;
+ MapScopeDepth = 0;
+ Link = NULL;
+ VarStorage = NULL;
+ MapExpressionList = NULL;
+ TempVarstoreId = 0;
+ ConstantFlag = TRUE;
+ BitFieldStorage = FALSE;
+
+ //
+ // Get the number of Statements and Expressions
+ //
+ CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);
+
+ mStatementIndex = 0;
+ FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));
+ if (FormSet->StatementBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mExpressionOpCodeIndex = 0;
+ FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE));
+ if (FormSet->ExpressionBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FormSet->StorageListHead = &mVarListEntry;
+ InitializeListHead (&FormSet->DefaultStoreListHead);
+ InitializeListHead (&FormSet->FormListHead);
+ InitializeListHead (&FormSet->ExpressionListHead);
+ ResetCurrentExpressionStack ();
+ ResetMapExpressionListStack ();
+
+ CurrentForm = NULL;
+ CurrentStatement = NULL;
+
+ ResetScopeStack ();
+
+ OpCodeOffset = 0;
+ while (OpCodeOffset < FormSet->IfrBinaryLength) {
+ OpCodeData = FormSet->IfrBinaryData + OpCodeOffset;
+
+ OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ OpCodeOffset += OpCodeLength;
+ Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+ Scope = ((EFI_IFR_OP_HEADER *) OpCodeData)->Scope;
+
+ //
+ // If scope bit set, push onto scope stack
+ //
+ if (Scope != 0) {
+ PushScope (Operand);
+ }
+
+ if (OpCodeDisabled) {
+ //
+ // DisableIf Expression is evaluated to be TRUE, try to find its end.
+ // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END
+ //
+ if (Operand == EFI_IFR_DISABLE_IF_OP) {
+ DepthOfDisable++;
+ } else if (Operand == EFI_IFR_END_OP) {
+ Status = PopScope (&ScopeOpCode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) {
+ if (DepthOfDisable == 0) {
+ mInScopeDisable = FALSE;
+ OpCodeDisabled = FALSE;
+ } else {
+ DepthOfDisable--;
+ }
+ }
+ }
+ continue;
+ }
+
+ if (IsExpressionOpCode (Operand)) {
+ ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex];
+ mExpressionOpCodeIndex++;
+
+ ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE;
+ ExpressionOpCode->Operand = Operand;
+ Value = &ExpressionOpCode->Value;
+
+ switch (Operand) {
+ case EFI_IFR_EQ_ID_VAL_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->Value, sizeof (UINT16));
+ break;
+
+ case EFI_IFR_EQ_ID_ID_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID));
+ CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID));
+ break;
+
+ case EFI_IFR_EQ_ID_VAL_LIST_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+ CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ListLength, sizeof (UINT16));
+ ExpressionOpCode->ValueList = FceAllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ValueList);
+ break;
+
+ case EFI_IFR_TO_STRING_OP:
+ case EFI_IFR_FIND_OP:
+ ExpressionOpCode->Format = (( EFI_IFR_TO_STRING *) OpCodeData)->Format;
+ break;
+
+ case EFI_IFR_STRING_REF1_OP:
+ Value->Type = EFI_IFR_TYPE_STRING;
+ CopyMem (&Value->Value.string, &(( EFI_IFR_STRING_REF1 *) OpCodeData)->StringId, sizeof (EFI_STRING_ID));
+ break;
+
+ case EFI_IFR_RULE_REF_OP:
+ ExpressionOpCode->RuleId = (( EFI_IFR_RULE_REF *) OpCodeData)->RuleId;
+ break;
+
+ case EFI_IFR_SPAN_OP:
+ ExpressionOpCode->Flags = (( EFI_IFR_SPAN *) OpCodeData)->Flags;
+ break;
+
+ case EFI_IFR_THIS_OP:
+ ASSERT (CurrentStatement != NULL);
+ ExpressionOpCode->QuestionId = CurrentStatement->QuestionId;
+ break;
+
+ case EFI_IFR_SECURITY_OP:
+ CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_SECURITY *) OpCodeData)->Permissions, sizeof (EFI_GUID));
+ break;
+
+ case EFI_IFR_GET_OP:
+ case EFI_IFR_SET_OP:
+ CopyMem (&TempVarstoreId, &((EFI_IFR_GET *) OpCodeData)->VarStoreId, sizeof (TempVarstoreId));
+ if (TempVarstoreId != 0) {
+ if (FormSet->StorageListHead->ForwardLink != NULL) {
+ Link = GetFirstNode (FormSet->StorageListHead);
+ while (!IsNull (FormSet->StorageListHead, Link)) {
+ VarStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ if (VarStorage->VarStoreId == ((EFI_IFR_GET *) OpCodeData)->VarStoreId) {
+ ExpressionOpCode->VarStorage = VarStorage;
+ break;
+ }
+ Link = GetNextNode (FormSet->StorageListHead, Link);
+ }
+ }
+ if (ExpressionOpCode->VarStorage == NULL) {
+ //
+ // VarStorage is not found.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ ExpressionOpCode->ValueType = ((EFI_IFR_GET *) OpCodeData)->VarStoreType;
+ switch (ExpressionOpCode->ValueType) {
+ case EFI_IFR_TYPE_BOOLEAN:
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ ExpressionOpCode->ValueWidth = 1;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_STRING:
+ ExpressionOpCode->ValueWidth = 2;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ ExpressionOpCode->ValueWidth = 4;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ ExpressionOpCode->ValueWidth = 8;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_DATE);
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_TIME);
+ break;
+
+ case EFI_IFR_TYPE_REF:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_REF);
+ break;
+
+ case EFI_IFR_TYPE_OTHER:
+ case EFI_IFR_TYPE_UNDEFINED:
+ case EFI_IFR_TYPE_ACTION:
+ case EFI_IFR_TYPE_BUFFER:
+ default:
+ //
+ // Invalid value type for Get/Set opcode.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ CopyMem (&ExpressionOpCode->VarStoreInfo.VarName, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarName, sizeof (EFI_STRING_ID));
+ CopyMem (&ExpressionOpCode->VarStoreInfo.VarOffset, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarOffset, sizeof (UINT16));
+ if ((ExpressionOpCode->VarStorage != NULL) &&
+ ((ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_NAME_VALUE)
+ || ((ExpressionOpCode->VarStorage->Type == EFI_IFR_VARSTORE_EFI_OP) && !ExpressionOpCode->VarStorage->NewEfiVarstore))
+ ) {
+ ExpressionOpCode->ValueName = GetToken (ExpressionOpCode->VarStoreInfo.VarName, FormSet->UnicodeBinary);
+ if (ExpressionOpCode->ValueName == NULL) {
+ //
+ // String ID is invalid.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ case EFI_IFR_QUESTION_REF1_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+ break;
+
+ case EFI_IFR_QUESTION_REF3_OP:
+ if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) {
+ CopyMem (&ExpressionOpCode->DevicePath, &(( EFI_IFR_QUESTION_REF3_2 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) {
+ CopyMem (&ExpressionOpCode->Guid, &(( EFI_IFR_QUESTION_REF3_3 *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ }
+ }
+ break;
+
+ //
+ // constant
+ //
+ case EFI_IFR_TRUE_OP:
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Value->Value.b = TRUE;
+ break;
+
+ case EFI_IFR_FALSE_OP:
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Value->Value.b = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = 1;
+ break;
+
+ case EFI_IFR_ZERO_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = 0;
+ break;
+
+ case EFI_IFR_ONES_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = 0xffffffffffffffffULL;
+ break;
+
+ case EFI_IFR_UINT8_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = (( EFI_IFR_UINT8 *) OpCodeData)->Value;
+ break;
+
+ case EFI_IFR_UINT16_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ CopyMem (&Value->Value.u16, &(( EFI_IFR_UINT16 *) OpCodeData)->Value, sizeof (UINT16));
+ break;
+
+ case EFI_IFR_UINT32_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ CopyMem (&Value->Value.u32, &(( EFI_IFR_UINT32 *) OpCodeData)->Value, sizeof (UINT32));
+ break;
+
+ case EFI_IFR_UINT64_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ CopyMem (&Value->Value.u64, &(( EFI_IFR_UINT64 *) OpCodeData)->Value, sizeof (UINT64));
+ break;
+
+ case EFI_IFR_UNDEFINED_OP:
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+
+ case EFI_IFR_VERSION_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+
+ default:
+ break;
+ }
+ //
+ // Create sub expression nested in MAP opcode
+ //
+ if ((CurrentExpression == NULL) && (MapScopeDepth > 0)) {
+ CurrentExpression = CreateExpression (CurrentForm);
+ ASSERT (MapExpressionList != NULL);
+ InsertTailList (MapExpressionList, &CurrentExpression->Link);
+ if (Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ }
+ ASSERT (CurrentExpression != NULL);
+ InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link);
+ if (Operand == EFI_IFR_MAP_OP) {
+ //
+ // Store current Map Expression List.
+ //
+ if (MapExpressionList != NULL) {
+ PushMapExpressionList (MapExpressionList);
+ }
+ //
+ // Initialize new Map Expression List.
+ //
+ MapExpressionList = &ExpressionOpCode->MapExpressionList;
+ InitializeListHead (MapExpressionList);
+ //
+ // Store current expression.
+ //
+ PushCurrentExpression (CurrentExpression);
+ CurrentExpression = NULL;
+ MapScopeDepth ++;
+ } else if (SingleOpCodeExpression) {
+ //
+ // There are two cases to indicate the end of an Expression:
+ // for single OpCode expression: one Expression OpCode
+ // for expression consists of more than one OpCode: EFI_IFR_END
+ //
+ SingleOpCodeExpression = FALSE;
+
+ if (mInScopeDisable && (CurrentForm == NULL)) {
+ //
+ // This is DisableIf expression for Form, it should be a constant expression
+ //
+ ConstantFlag = TRUE;
+ Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!ConstantFlag) {
+ StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
+ }
+ OpCodeDisabled = CurrentExpression->Result.Value.b;
+ }
+
+ CurrentExpression = NULL;
+ }
+
+ continue;
+ }
+
+ //
+ // Parse the Opcode
+ //
+ switch (Operand) {
+
+ case EFI_IFR_FORM_SET_OP:
+
+ CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
+ CopyMem (&FormSet->Help, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
+ CopyMem (&FormSet->Guid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
+
+ if (OpCodeLength > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
+ //
+ // The formset OpCode contains ClassGuid
+ //
+ FormSet->NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
+ CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID));
+ }
+ FormSet->FormSetOrder = ++mFormSetOrderParse;
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // Create a new Form for this FormSet
+ //
+ CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
+ ASSERT (CurrentForm != NULL);
+ CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
+ InitializeListHead (&CurrentForm->ExpressionListHead);
+ InitializeListHead (&CurrentForm->StatementListHead);
+
+ CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
+ CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16));
+ CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));
+
+ if (InScopeFormSuppress) {
+ //
+ // Form is inside of suppressif
+ //
+ CurrentForm->SuppressExpression = FormSuppressExpression;
+ }
+
+ if (Scope != 0) {
+ //
+ // Enter scope of a Form, suppressif will be used for Question or Option
+ //
+ SuppressForQuestion = TRUE;
+ }
+
+ //
+ // Insert into Form list of this FormSet
+ //
+ InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
+ break;
+ //
+ // Storage
+ //
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // Create a buffer Storage for this FormSet
+ //
+
+ Storage = CreateStorage (FormSet);
+ Storage->Type = EFI_IFR_VARSTORE_OP;
+
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16));
+
+ Storage->Buffer = AllocateZeroPool (Storage->Size);
+
+ AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
+ Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
+ ASSERT (Storage->Name != NULL);
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ Storage->Name[Index] = (CHAR16) AsciiString[Index];
+ }
+ Storage->FormSetOrder = mFormSetOrderParse;
+
+ //
+ // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
+ // If these two variales have the same Guid name but different size, report an error.
+ //
+ if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
+ if (Storage->Size != TempStorage->Size) {
+ StringPrint ("Error. Two modules found with VarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but with different sizes %d and %d.\n",
+ Storage->Name,
+ Storage->Guid.Data1,
+ Storage->Guid.Data2,
+ Storage->Guid.Data3,
+ Storage->Guid.Data4[0],
+ Storage->Guid.Data4[1],
+ Storage->Guid.Data4[2],
+ Storage->Guid.Data4[3],
+ Storage->Guid.Data4[4],
+ Storage->Guid.Data4[5],
+ Storage->Guid.Data4[6],
+ Storage->Guid.Data4[7],
+ Storage->Size,
+ TempStorage->Size
+ );
+ return EFI_ABORTED;
+ }
+ //
+ // Update the VarStoreId for current question to get the variable guid and name information
+ //
+ TempStorage->VarStoreId = Storage->VarStoreId;
+ TempStorage->FormSetOrder = Storage->FormSetOrder;
+ RemoveEntryList (&Storage->Link);
+ DestroyStorage(Storage);
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ //
+ // Create a name/value Storage for this FormSet
+ //
+ Storage = CreateStorage (FormSet);
+ Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;
+
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+
+ Storage->FormSetOrder = mFormSetOrderParse;
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // Create a EFI variable Storage for this FormSet
+ //
+ Storage = CreateStorage (FormSet);
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&Storage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32));
+ //
+ // Check whether the EfiVarStore before UEFI2.31 or not
+ //
+ Storage->Size = sizeof (EFI_IFR_VARSTORE_EFI_OLD);
+ if (((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Header.Length == sizeof (EFI_IFR_VARSTORE_EFI_OLD)) {
+ Storage->NewEfiVarstore = FALSE;
+ Storage->Size = 0;
+ Storage->Buffer = NULL;
+ Storage->Name = NULL;
+ Storage->Size = 0;
+ } else {
+ //
+ // EfiVarStore structure for UEFI2.31
+ //
+ Storage->NewEfiVarstore = TRUE;
+ CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Size, sizeof (UINT16));
+
+ Storage->Buffer = AllocateZeroPool (Storage->Size);
+ AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
+ Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
+ ASSERT (Storage->Name != NULL);
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ Storage->Name[Index] = (CHAR16) AsciiString[Index];
+ }
+ }
+ Storage->FormSetOrder = mFormSetOrderParse;
+ //
+ // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
+ // If these two variales have the same Guid name but different size, report an error.
+ //
+ if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
+ if (Storage->Size != TempStorage->Size) {
+ StringPrint ("Error. Two modules found with EfiVarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but different sizes %d and %d.\n",
+ Storage->Name,
+ Storage->Guid.Data1,
+ Storage->Guid.Data2,
+ Storage->Guid.Data3,
+ Storage->Guid.Data4[0],
+ Storage->Guid.Data4[1],
+ Storage->Guid.Data4[2],
+ Storage->Guid.Data4[3],
+ Storage->Guid.Data4[4],
+ Storage->Guid.Data4[5],
+ Storage->Guid.Data4[6],
+ Storage->Guid.Data4[7],
+ Storage->Size,
+ TempStorage->Size
+ );
+ return EFI_ABORTED;
+ }
+ //
+ // Update the VarStoreId for current question to get the variable guid and name information
+ //
+ TempStorage->VarStoreId = Storage->VarStoreId;
+ TempStorage->FormSetOrder = Storage->FormSetOrder;
+ RemoveEntryList (&Storage->Link);
+ DestroyStorage( Storage);
+ }
+ break;
+
+ //
+ // DefaultStore
+ //
+ case EFI_IFR_DEFAULTSTORE_OP:
+ HaveInserted = FALSE;
+ DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE));
+ ASSERT (DefaultStore != NULL);
+ DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE;
+
+ CopyMem (&DefaultStore->DefaultId, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultId, sizeof (UINT16));
+ CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultName, sizeof (EFI_STRING_ID));
+
+ //
+ // Insert it to the DefaultStore list of this Formset with ascending order.
+ //
+ if (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+ DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+ while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
+ PreDefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+ DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
+ if (DefaultStore->DefaultId < PreDefaultStore->DefaultId) {
+ InsertTailList (&PreDefaultStore->Link, &DefaultStore->Link);
+ HaveInserted = TRUE;
+ break;
+ }
+ }
+ }
+ if (!HaveInserted) {
+ InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link);
+ }
+ break;
+
+ //
+ // Statements
+ //
+ case EFI_IFR_SUBTITLE_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;
+
+ if (Scope != 0) {
+ mInScopeSubtitle = TRUE;
+ }
+ break;
+
+ case EFI_IFR_TEXT_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+
+ CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));
+ break;
+
+ case EFI_IFR_RESET_BUTTON_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));
+ break;
+
+ //
+ // Questions
+ //
+ case EFI_IFR_ACTION_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_ACTION;
+ //
+ // No need to deal with the EFI_IFR_ACTION
+ //
+ break;
+
+ case EFI_IFR_REF_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ Value = &CurrentStatement->HiiValue;
+ Value->Type = EFI_IFR_TYPE_REF;
+ if (OpCodeLength >= sizeof (EFI_IFR_REF)) {
+ CopyMem (&Value->Value.ref.FormId, &((EFI_IFR_REF *) OpCodeData)->FormId, sizeof (EFI_FORM_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF2)) {
+ CopyMem (&Value->Value.ref.QuestionId, &((EFI_IFR_REF2 *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF3)) {
+ CopyMem (&Value->Value.ref.FormSetGuid, &((EFI_IFR_REF3 *) OpCodeData)->FormSetId, sizeof (EFI_GUID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF4)) {
+ CopyMem (&Value->Value.ref.DevicePath, &((EFI_IFR_REF4 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+ }
+ }
+ }
+ }
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_REF);
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_ONE_OF *) OpCodeData)->Flags;
+ Value = &CurrentStatement->HiiValue;
+
+ if (BitFieldStorage) {
+ //
+ // Get the bit var store info (bit/byte offset, bit/byte offset)
+ //
+ CurrentStatement->QuestionReferToBitField = TRUE;
+ CurrentStatement->BitStorageWidth = CurrentStatement->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+ CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+ TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+ CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+ //
+ // Get the Minimum/Maximum/Step value(Note: bit field type has been stored as UINT32 type)
+ //
+ CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue;
+ CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue;
+ CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step;
+ } else {
+ switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue;
+ CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue;
+ CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step;
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT8);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step, sizeof (UINT16));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT16);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue, sizeof (UINT32));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue, sizeof (UINT32));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step, sizeof (UINT32));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT32);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MinValue, sizeof (UINT64));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MaxValue, sizeof (UINT64));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.Step, sizeof (UINT64));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT64);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if ((Operand == EFI_IFR_ONE_OF_OP) && (Scope != 0)) {
+ SuppressForOption = TRUE;
+ }
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Flags;
+ CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BUFFER;
+ CurrentStatement->BufferValue = NULL;
+ if (Scope != 0) {
+ SuppressForOption = TRUE;
+ }
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *) OpCodeData)->Flags;
+ CurrentStatement->StorageWidth = (UINT16) sizeof (BOOLEAN);
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN;
+
+ if (BitFieldStorage) {
+ //
+ // Get the bit var store info (bit/byte offset, bit/byte width)
+ //
+ CurrentStatement->QuestionReferToBitField = TRUE;
+ CurrentStatement->BitStorageWidth = 1;
+ CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+ CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+ TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+ CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+ }
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+
+ break;
+
+ case EFI_IFR_STRING_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ //
+ // MinSize is the minimum number of characters that can be accepted for this opcode,
+ // MaxSize is the maximum number of characters that can be accepted for this opcode.
+ // The characters are stored as Unicode, so the storage width should multiply 2.
+ //
+ CurrentStatement->Minimum = ((EFI_IFR_STRING *) OpCodeData)->MinSize;
+ CurrentStatement->Maximum = ((EFI_IFR_STRING *) OpCodeData)->MaxSize;
+ CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+ CurrentStatement->Flags = ((EFI_IFR_STRING *) OpCodeData)->Flags;
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+ CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth + sizeof (CHAR16));
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+
+ break;
+
+ case EFI_IFR_PASSWORD_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ //
+ // MinSize is the minimum number of characters that can be accepted for this opcode,
+ // MaxSize is the maximum number of characters that can be accepted for this opcode.
+ // The characters are stored as Unicode, so the storage width should multiply 2.
+ //
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *) OpCodeData)->MinSize, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize, sizeof (UINT16));
+ CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+ CurrentStatement->BufferValue = AllocateZeroPool ((CurrentStatement->StorageWidth + sizeof (CHAR16)));
+ break;
+
+ case EFI_IFR_DATE_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_DATE *) OpCodeData)->Flags;
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE;
+
+ if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) {
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_DATE);
+ } else {
+ //
+ // Don't assign storage for RTC type of date/time
+ //
+ CurrentStatement->Storage = NULL;
+ CurrentStatement->StorageWidth = 0;
+ }
+ break;
+
+ case EFI_IFR_TIME_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_TIME *) OpCodeData)->Flags;
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME;
+
+ if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) {
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_TIME);
+ } else {
+ //
+ // Don't assign storage for RTC type of date/time
+ //
+ CurrentStatement->Storage = NULL;
+ CurrentStatement->StorageWidth = 0;
+ }
+ break;
+
+ //
+ // Default
+ //
+ case EFI_IFR_DEFAULT_OP:
+ //
+ // EFI_IFR_DEFAULT appear in scope of a Question,
+ // It creates a default value for the current question.
+ // A Question may have more than one Default value which have different default types.
+ //
+ CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
+ ASSERT (CurrentDefault != NULL);
+ CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+ CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *) OpCodeData)->Type;
+ CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *) OpCodeData)->DefaultId, sizeof (UINT16));
+ if (CurrentDefault->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
+ CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_DEFAULT *)OpCodeData)->Value);
+ ASSERT(CurrentDefault->Value.Buffer != NULL);
+ } else {
+ CopyMem(&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *)OpCodeData)->Value, OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
+ ExtendValueToU64(&CurrentDefault->Value);
+ }
+
+ //
+ // Insert to Default Value list of current Question
+ //
+ InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link);
+
+ if (Scope != 0) {
+ InScopeDefault = TRUE;
+ }
+ break;
+
+ //
+ // Option
+ //
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ ASSERT (CurrentStatement != NULL);
+ if (CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP &&
+ ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)) != 0)) {
+ //
+ // It's keep the default value for ordered list opcode.
+ //
+ CurrentDefault = AllocateZeroPool(sizeof (QUESTION_DEFAULT));
+ ASSERT(CurrentDefault != NULL);
+ CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+ CurrentDefault->Value.Type = EFI_IFR_TYPE_BUFFER;
+ if ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & EFI_IFR_OPTION_DEFAULT) != 0) {
+ CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ } else {
+ CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ }
+
+ CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value));
+ CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value);
+ ASSERT(CurrentDefault->Value.Buffer != NULL);
+
+ //
+ // Insert to Default Value list of current Question
+ //
+ InsertTailList(&CurrentStatement->DefaultListHead, &CurrentDefault->Link);
+ break;
+ }
+ //
+ // EFI_IFR_ONE_OF_OPTION appear in scope of a Question.
+ // It create a selection for use in current Question.
+ //
+ CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));
+ ASSERT (CurrentOption != NULL);
+ CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;
+
+ CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags;
+ CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type;
+ CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Option, sizeof (EFI_STRING_ID));
+ CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ ExtendValueToU64 (&CurrentOption->Value);
+
+ if (InScopeOptionSuppress) {
+ CurrentOption->SuppressExpression = OptionSuppressExpression;
+ }
+
+ //
+ // Insert to Option list of current Question
+ //
+ InsertTailList (&CurrentStatement->OptionListHead, &CurrentOption->Link);
+
+ //
+ // Now we know the Storage width of nested Ordered List
+ //
+ if ((CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (CurrentStatement->BufferValue == NULL)) {
+ Width = 1;
+ switch (CurrentOption->Value.Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Width = 1;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Width = 2;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Width = 4;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ Width = 8;
+ break;
+
+ default:
+ //
+ // Invalid type for Ordered List
+ //
+ break;
+ }
+
+ CurrentStatement->StorageWidth = (UINT16) (CurrentStatement->MaxContainers * Width);
+ CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth);
+ CurrentStatement->ValueType = CurrentOption->Value.Type;
+ if (CurrentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
+ CurrentStatement->HiiValue.Buffer = CurrentStatement->BufferValue;
+ CurrentStatement->HiiValue.BufferLen = CurrentStatement->StorageWidth;
+ }
+ }
+ break;
+
+ //
+ // Conditional
+ //
+ case EFI_IFR_NO_SUBMIT_IF_OP:
+ case EFI_IFR_INCONSISTENT_IF_OP:
+ //
+ // Create an Expression node
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID));
+
+ if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) {
+ CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF;
+ InsertTailList (&CurrentStatement->NoSubmitListHead, &CurrentExpression->Link);
+ } else {
+ CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF;
+ InsertTailList (&CurrentStatement->InconsistentListHead, &CurrentExpression->Link);
+ }
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_WARNING_IF_OP:
+ //
+ // Create an Expression node
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *) OpCodeData)->Warning, sizeof (EFI_STRING_ID));
+ CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeData)->TimeOut;
+ CurrentExpression->Type = EFI_HII_EXPRESSION_WARNING_IF;
+ InsertTailList (&CurrentStatement->WarningListHead, &CurrentExpression->Link);
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_SUPPRESS_IF_OP:
+ //
+ // Question and Option will appear in scope of this OpCode
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF;
+
+ if (CurrentForm == NULL) {
+ InsertTailList (&FormSet->ExpressionListHead, &CurrentExpression->Link);
+ } else {
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+ }
+
+ if (SuppressForOption) {
+ InScopeOptionSuppress = TRUE;
+ OptionSuppressExpression = CurrentExpression;
+ } else if (SuppressForQuestion) {
+ mInScopeSuppress = TRUE;
+ mSuppressExpression = CurrentExpression;
+ } else {
+ InScopeFormSuppress = TRUE;
+ FormSuppressExpression = CurrentExpression;
+ }
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_GRAY_OUT_IF_OP:
+ //
+ // Questions will appear in scope of this OpCode
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ mInScopeGrayOut = TRUE;
+ mGrayOutExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_DISABLE_IF_OP:
+ //
+ // The DisableIf expression should only rely on constant, so it could be
+ // evaluated at initialization and it will not be queued
+ //
+ CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+ ASSERT (CurrentExpression != NULL);
+ CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE;
+ CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF;
+ InitializeListHead (&CurrentExpression->OpCodeListHead);
+
+ if (CurrentForm != NULL) {
+ //
+ // This is DisableIf for Question, enqueue it to Form expression list
+ //
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+ }
+
+ mDisableExpression = CurrentExpression;
+ mInScopeDisable = TRUE;
+ OpCodeDisabled = FALSE;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ //
+ // Expression
+ //
+ case EFI_IFR_VALUE_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ if (InScopeDefault) {
+ //
+ // Used for default (EFI_IFR_DEFAULT)
+ //
+ CurrentDefault->ValueExpression = CurrentExpression;
+ } else {
+ //
+ // If used for a question, then the question will be read-only
+ //
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->ValueExpression = CurrentExpression;
+ }
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_RULE_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_RULE;
+
+ CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_READ_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_READ;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->ReadExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_WRITE_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->WriteExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ //
+ // Image
+ //
+ case EFI_IFR_IMAGE_OP:
+ //
+ // Get ScopeOpcode from top of stack
+ //
+ PopScope (&ScopeOpCode);
+ PushScope (ScopeOpCode);
+
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ ASSERT (CurrentForm != NULL);
+ break;
+
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ break;
+
+ default:
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ break;
+ }
+ break;
+
+ //
+ // Refresh
+ //
+ case EFI_IFR_REFRESH_OP:
+ break;
+
+ //
+ // Refresh guid.
+ //
+ case EFI_IFR_REFRESH_ID_OP:
+ break;
+
+ //
+ // Modal tag
+ //
+ case EFI_IFR_MODAL_TAG_OP:
+ break;
+
+ //
+ // Vendor specific
+ //
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid ((EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarGuid)==0) {
+ Scope = 0;
+ BitFieldStorage = TRUE;
+ }
+ break;
+
+ //
+ // Scope End
+ //
+ case EFI_IFR_END_OP:
+ BitFieldStorage = FALSE;
+ Status = PopScope (&ScopeOpCode);
+ if (EFI_ERROR (Status)) {
+ ResetScopeStack ();
+ return Status;
+ }
+
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ //
+ // End of FormSet, update FormSet IFR binary length
+ // to stop parsing substantial OpCodes
+ //
+ FormSet->IfrBinaryLength = OpCodeOffset;
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // End of Form
+ //
+ CurrentForm = NULL;
+ SuppressForQuestion = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ //
+ // End of Option
+ //
+ CurrentOption = NULL;
+ break;
+
+ case EFI_IFR_SUBTITLE_OP:
+ mInScopeSubtitle = FALSE;
+ break;
+
+ case EFI_IFR_NO_SUBMIT_IF_OP:
+ case EFI_IFR_INCONSISTENT_IF_OP:
+ case EFI_IFR_WARNING_IF_OP:
+ //
+ // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF
+ //
+ break;
+
+ case EFI_IFR_SUPPRESS_IF_OP:
+ if (SuppressForOption) {
+ InScopeOptionSuppress = FALSE;
+ } else if (SuppressForQuestion) {
+ mInScopeSuppress = FALSE;
+ } else {
+ InScopeFormSuppress = FALSE;
+ }
+ break;
+
+ case EFI_IFR_GRAY_OUT_IF_OP:
+ mInScopeGrayOut = FALSE;
+ break;
+
+ case EFI_IFR_DISABLE_IF_OP:
+ mInScopeDisable = FALSE;
+ OpCodeDisabled = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_ORDERED_LIST_OP:
+ SuppressForOption = FALSE;
+ break;
+
+ case EFI_IFR_DEFAULT_OP:
+ InScopeDefault = FALSE;
+ break;
+
+ case EFI_IFR_MAP_OP:
+ //
+ // Get current Map Expression List.
+ //
+ Status = PopMapExpressionList ((VOID **) &MapExpressionList);
+ if (Status == EFI_ACCESS_DENIED) {
+ MapExpressionList = NULL;
+ }
+ //
+ // Get current expression.
+ //
+ Status = PopCurrentExpression ((VOID **) &CurrentExpression);
+ ASSERT (!EFI_ERROR (Status));
+ ASSERT (MapScopeDepth > 0);
+ MapScopeDepth --;
+ break;
+
+ default:
+ if (IsExpressionOpCode (ScopeOpCode)) {
+ if (mInScopeDisable && (CurrentForm == NULL)) {
+ //
+ // This is DisableIf expression for Form, it should be a constant expression
+ //
+ ASSERT (CurrentExpression != NULL);
+ ConstantFlag = TRUE;
+ Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!ConstantFlag) {
+ StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
+ }
+ OpCodeDisabled = CurrentExpression->Result.Value.b;
+ //
+ // DisableIf Expression is only used once and not queued, free it
+ //
+ DestroyExpression (CurrentExpression);
+ }
+
+ //
+ // End of current Expression
+ //
+ CurrentExpression = NULL;
+ }
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search an Option of a Question by its value.
+
+ @param Question The Question
+ @param OptionValue Value for Option to be searched.
+
+ @retval Pointer Pointer to the found Option.
+ @retval NULL Option not found.
+
+**/
+QUESTION_OPTION *
+ValueToOption (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ if (CompareHiiValue (&Option->Value, OptionValue, FormSet) == 0) {
+ return Option;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Set value of a data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+ @param Value The value to be set.
+
+**/
+VOID
+SetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index,
+ IN UINT64 Value
+ )
+{
+
+ ASSERT (Array != NULL);
+
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ *(((UINT8 *) Array) + Index) = (UINT8) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ *(((UINT16 *) Array) + Index) = (UINT16) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ *(((UINT32 *) Array) + Index) = (UINT32) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ *(((UINT64 *) Array) + Index) = (UINT64) Value;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Reset Question of five kinds to its default value.
+
+ @param FormSet The form set.
+ @param Form The form.
+ @param Question The question.
+ @param DefaultId The default Id.
+ @param DefaultId The platform Id.
+
+ @retval EFI_SUCCESS Question is reset to default value.
+
+**/
+EFI_STATUS
+GetQuestionDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ QUESTION_DEFAULT *Default;
+ QUESTION_OPTION *Option;
+ EFI_HII_VALUE *HiiValue;
+ UINT8 Index;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+ BOOLEAN ConstantFlag;
+ UINT16 OriginalDefaultId;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ LIST_ENTRY *DefaultLink;
+ CHAR16 *VarDefaultName;
+
+ VarDefaultName = NULL;
+ Status = EFI_SUCCESS;
+ ConstantFlag = TRUE;
+ OriginalDefaultId = DefaultId;
+ DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+ //
+ // Statement don't have storage, skip them
+ //
+ if (Question->QuestionId == 0) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Return if no any kinds of
+ //
+ if ((Question->Operand != EFI_IFR_CHECKBOX_OP)
+ && (Question->Operand != EFI_IFR_ONE_OF_OP)
+ && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
+ && (Question->Operand != EFI_IFR_NUMERIC_OP)
+ && (Question->Operand != EFI_IFR_STRING_OP)
+ ) {
+ return EFI_ABORTED;
+ }
+ //
+ // Search the variable for this question (Compatible with the old EfiVarStore before UEFI2.31)
+ //
+
+ //
+ //VarStoreInfoDepending on the type of variable store selected,
+ //this contains either a 16-bit Buffer Storage offset (VarOffset)
+ //or a Name/Value or EFI Variable name (VarName).
+ //
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ //
+ // There are three ways to specify default value for a Question:
+ // 1, use nested EFI_IFR_DEFAULT
+ // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
+ // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
+ //
+ReGetDefault:
+ HiiValue = &Question->HiiValue;
+ //
+ // EFI_IFR_DEFAULT has highest priority
+ //
+ if (!IsListEmpty (&Question->DefaultListHead)) {
+ Link = GetFirstNode (&Question->DefaultListHead);
+ while (!IsNull (&Question->DefaultListHead, Link)) {
+ Default = QUESTION_DEFAULT_FROM_LINK (Link);
+
+ if (Default->DefaultId == DefaultId) {
+ if (Default->ValueExpression != NULL) {
+ //
+ // Default is provided by an Expression, evaluate it
+ //
+ Status = EvaluateExpression (FormSet, Form, Default->ValueExpression, &ConstantFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
+ if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
+ CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
+ Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
+ } else {
+ CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
+ Question->HiiValue.BufferLen = Question->StorageWidth;
+ }
+ FreePool(Default->ValueExpression->Result.Buffer);
+ }
+ HiiValue->Type = Default->ValueExpression->Result.Type;
+ CopyMem(&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
+ } else {
+ //
+ // Default value is embedded in EFI_IFR_DEFAULT
+ //
+ if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ CopyMem(HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
+ } else {
+ CopyMem(HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
+ }
+ }
+ if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ CopyMem(VarBuffer, HiiValue->Buffer, HiiValue->BufferLen);
+ } else if (HiiValue->Type == EFI_IFR_TYPE_STRING){
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ HiiValue->Value.string,
+ EN_US,
+ &VarDefaultName
+ );
+ if (VarDefaultName == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ if (Question->StorageWidth > FceStrSize(VarDefaultName)) {
+ ZeroMem (VarBuffer, Question->StorageWidth);
+ CopyMem (VarBuffer, VarDefaultName, FceStrSize(VarDefaultName));
+ } else {
+ CopyMem (VarBuffer, VarDefaultName, Question->StorageWidth);
+ }
+ } else {
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem(VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ }
+ return EFI_SUCCESS;
+ }
+ if (Default->DefaultId == DefaultId) {
+ return EFI_SUCCESS;
+ }
+ Link = GetNextNode (&Question->DefaultListHead, Link);
+ }
+ }
+
+ if (HiiValue->Buffer == NULL) {
+ ZeroMem (HiiValue, sizeof (EFI_HII_VALUE));
+ }
+
+ //
+ // EFI_ONE_OF_OPTION
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // OneOfOption could only provide Standard and Manufacturing default
+ //
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
+ ) {
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+ }
+ }
+
+ //
+ // EFI_IFR_CHECKBOX - lowest priority
+ //
+ if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // Checkbox could only provide Standard and Manufacturing default
+ //
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
+ ) {
+ HiiValue->Value.b = TRUE;
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
+ // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
+ // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
+ //
+ while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) {
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+ DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink);
+ DefaultId = DefaultStore->DefaultId;
+ if (DefaultId == OriginalDefaultId) {
+ continue;
+ }
+ goto ReGetDefault;
+ }
+
+ //
+ // For Questions without default
+ //
+ Status = EFI_NOT_FOUND;
+ switch (Question->Operand) {
+ case EFI_IFR_CHECKBOX_OP:
+ HiiValue->Value.b = FALSE;
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ //
+ // Take minimum value as numeric default value
+ //
+ if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
+ HiiValue->Value.u64 = Question->Minimum;
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ //
+ // Take first oneof option as oneof's default value
+ //
+ if (ValueToOption (FormSet, Question, HiiValue) == NULL) {
+ Link = GetFirstNode (&Question->OptionListHead);
+ if (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ //
+ // Take option sequence in IFR as ordered list's default value
+ //
+ Index = 0;
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
+ SetArrayData (VarBuffer, Question->ValueType, Index, Option->Value.Value.u64);
+
+ Index++;
+ if (Index >= Question->MaxContainers) {
+ break;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the value to the variable of platformId question.
+
+ @param PlatformId The form set.
+
+ @retval EFI_SUCCESS Set successfully.
+
+**/
+EFI_STATUS
+AssignThePlatformId (
+ IN UINT64 PlatformId
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+
+ Status = EFI_SUCCESS;
+ VarBuffer = NULL;
+ //
+ // Set the Storage
+ //
+ Status = SearchVarStorage (
+ &mMultiPlatformParam.PlatformIdQuestion,
+ NULL,
+ mMultiPlatformParam.PlatformIdQuestion.VarStoreInfo.VarOffset,
+ &mVarListEntry,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ CopyMem (VarBuffer, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
+ //
+ // Set the HIIvalue of this questions
+ //
+ CopyMem (&mMultiPlatformParam.Question->HiiValue.Value.u64, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
+
+ switch (mMultiPlatformParam.PlatformIdWidth) {
+ case sizeof (UINT8):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ break;
+
+ case sizeof (UINT16):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+
+ case sizeof (UINT32):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ break;
+
+ case sizeof (UINT64):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ break;
+
+ default:
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Reset Questions to their default value in a Form, Formset or System.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param DefaultId The default Id
+ @param PlatformId The platform Id
+ @param SettingScope Setting Scope for Default action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *FormLink;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *FormSetEntryListHead;
+ FORM_BROWSER_STATEMENT *Question;
+ //
+ // Check the supported setting level.
+ //
+ if (SettingScope >= MaxLevel) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (SettingScope == FormLevel) {
+ //
+ // Extract Form default
+ //
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ //
+ // Re-set the platformId before calcuate the platformId of every question to avoid over-written.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ Status = AssignThePlatformId (PlatformId);
+ if (EFI_ERROR (Status)) {
+ StringPrint ("Error. Failed to assign the platformId.\n");
+ return Status;
+ }
+ }
+ //
+ // Reset Question to its default value, and store the default to variable
+ //
+ Status = GetQuestionDefault (FormSet, Form, Question, DefaultId, PlatformId);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ }
+ } else if (SettingScope == FormSetLevel) {
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ ExtractDefault (FormSet, Form, DefaultId, PlatformId, FormLevel);
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ } else if (SettingScope == SystemLevel) {
+ //
+ // Parse Fromset one by one
+ //
+ FormSetEntryListHead = &mFormSetListEntry;
+
+ FormLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
+ ExtractDefault (FormSet, NULL, DefaultId, PlatformId, FormSetLevel);
+ FormLink = GetNextNode (FormSetEntryListHead, FormLink);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether existed the UQI in Current Unicode String.
+
+ @param UniPackge A pointer to a Null-terminated Unicode string Array.
+
+ @return TRUE If find the uqi, return TRUE
+ @return FALSE Otherwise, return FALSE
+
+**/
+static
+BOOLEAN
+IsUqiOrNot (
+ IN UINT8 *UniPackge
+ )
+{
+ CHAR8 *UniBin;
+ UINTN UniLength;
+ UINTN Index;
+ BOOLEAN FindIt;
+
+ UniBin = (CHAR8 *) UniPackge + 4;
+ Index = 4;
+ FindIt = FALSE;
+ UniLength = *(UINT32 *) UniPackge;
+
+ if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ //
+ // Search the uqi language
+ //
+ while ((Index < UniLength) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS){
+ if (!strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi")) {
+ FindIt = TRUE;
+ break;
+ }
+ Index = Index + ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ }
+ return FindIt;
+}
+
+ /**
+ Returns Length of UQI string (in CHAR16) (not including null termination).
+
+ @param UniPackge A pointer to a UQI string.
+
+ @return Number Length of UQIL string (in words) or 0
+
+**/
+static
+UINT16
+GetUqiNum (
+ IN CHAR16 *UniString
+ )
+{
+ UINT16 Number;
+
+ if (UniString == NULL) {
+ return 0;
+ }
+ for (Number = 0; UniString[Number] != 0; Number++) {
+ ;
+ }
+ return Number;
+}
+
+/**
+ Print the formset title information.
+
+ @param FormSet The pointer to the formset.
+
+ @return NULL.
+
+**/
+static
+VOID
+StringPrintormSetTitle (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ VarDefaultName = NULL;
+
+ StringPrint("\n\n// Form Set: ");
+
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ FormSet->FormSetTitle,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+
+ StringPrint("\n// %s",FORM_SET_GUID_PREFIX);
+ StringPrint(
+ EFI_GUID_FORMAT,
+ FormSet->Guid.Data1, FormSet->Guid.Data2,
+ FormSet->Guid.Data3, FormSet->Guid.Data4[0],
+ FormSet->Guid.Data4[1],FormSet->Guid.Data4[2],
+ FormSet->Guid.Data4[3],FormSet->Guid.Data4[4],
+ FormSet->Guid.Data4[5],FormSet->Guid.Data4[6],
+ FormSet->Guid.Data4[7]);
+ StringPrint("\n");
+
+ if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && FormSet->FormSetTitle != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+}
+
+/**
+ Print the formset title information.
+
+ @param FormSet The pointer to the formset.
+ @param Question The pointer to the question of ONE_OF.
+
+ @return NULL.
+
+**/
+static
+EFI_STATUS
+PrintOneOfOptions (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ VarDefaultName = NULL;
+
+ if ((Question->Operand != EFI_IFR_ONE_OF_OP)
+ && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
+ ) {
+ return EFI_ABORTED;
+ }
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ if (Question->QuestionReferToBitField) {
+ StringPrint("// %08X = ", Option->Value.Value.u32);
+ } else {
+ switch(Option->Value.Type) {
+
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ StringPrint("// %02X = ", Option->Value.Value.u8);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ StringPrint("// %04X = ", Option->Value.Value.u16);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ StringPrint("// %08X = ", Option->Value.Value.u32);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ StringPrint("// %016llX = ", Option->Value.Value.u64);
+ break;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ StringPrint("// %X = ", Option->Value.Value.b);
+ break;
+
+ case EFI_IFR_TYPE_STRING:
+ StringPrint("// %X = ", Option->Value.Value.string);
+ break;
+
+ default:
+ break;
+ }
+ }
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Option->Text,
+ EN_US,
+ &VarDefaultName
+ );
+
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Option->Text != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+ return Status;
+}
+
+/**
+ Print the form title information.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+
+ @return NULL.
+
+**/
+static
+VOID
+StringPrintormTitle (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ VarDefaultName = NULL;
+
+ StringPrint("\n// Form: ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Form->FormTitle,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+
+ if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Form->FormTitle != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+
+}
+
+/**
+ Print the information of questions.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param Question The pointer to the question.
+ @param PrintOrNot Decide whether print or not.
+
+ @return NULL.
+
+**/
+static
+VOID
+PrintQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN BOOLEAN PrintOrNot
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VarDefaultName;
+ UINT16 UqiStringLength;
+ BOOLEAN HaveUQIlanguage;
+
+ Status = EFI_SUCCESS;
+ VarDefaultName = NULL;
+ UqiStringLength = 0;
+
+ HaveUQIlanguage = IsUqiOrNot (FormSet->UnicodeBinary);
+
+ switch (Question->Operand) {
+
+ case EFI_IFR_SUBTITLE_OP:
+ if (PrintOrNot) {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ if ((VarDefaultName != NULL) && (FceStrCmp (VarDefaultName, L"") != 0)) {
+ StringPrint("// Subtitle: ");
+ StringPrint("// ");
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ }
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the Question
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = ONE_OF;
+
+ if (PrintOrNot) {
+ StringPrint("ONE_OF ");
+
+ LogIfrValue (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ //
+ // Print ONE_OF_OPTION
+ //
+ PrintOneOfOptions (FormSet, Question);
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = CHECKBOX;
+ if (PrintOrNot) {
+ StringPrint("CHECKBOX ");
+ LogIfrValue (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ StringPrint("// 0 = Unchecked\n");
+ StringPrint("// 1 = Checked\n");
+ }
+ break;
+
+ case EFI_IFR_STRING_OP:
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = STRING;
+ if (PrintOrNot) {
+ StringPrint("STRING ");
+ LogIfrValueStr (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = NUMERIC;
+ if (PrintOrNot) {
+ StringPrint("NUMERIC ");
+ LogIfrValue (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+
+ if (Question->QuestionReferToBitField) {
+ StringPrint("// Minimum = %08llX \n", Question->Minimum);
+ StringPrint("// Maximum = %08llX \n", Question->Maximum);
+ StringPrint("// Step = %08llX \n", Question->Step);
+ } else {
+ switch (Question->StorageWidth) {
+
+ case sizeof (UINT8):
+ StringPrint("// Minimum = %02llX \n", Question->Minimum);
+ StringPrint("// Maximum = %02llX \n", Question->Maximum);
+ StringPrint("// Step = %02llX \n", Question->Step);
+ break;
+
+ case sizeof (UINT16):
+ StringPrint("// Minimum = %04llX \n", Question->Minimum);
+ StringPrint("// Maximum = %04llX \n", Question->Maximum);
+ StringPrint("// Step = %04llX \n", Question->Step);
+ break;
+
+ case sizeof (UINT32):
+ StringPrint("// Minimum = %08llX \n", Question->Minimum);
+ StringPrint("// Maximum = %08llX \n", Question->Maximum);
+ StringPrint("// Step = %08llX \n", Question->Step);
+ break;
+
+ case sizeof (UINT64):
+ StringPrint("// Minimum = %016llX \n", Question->Minimum);
+ StringPrint("// Maximum = %016llX \n", Question->Maximum);
+ StringPrint("// Step = %016llX \n", Question->Step);
+ break;
+
+ default:
+ StringPrint("0000 // Width > 16 is not supported -- FAILURE");
+ break;
+ }
+ }
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = ORDERED_LIST;
+
+ if (PrintOrNot) {
+ StringPrint("ORDERED_LIST %04X ", Question->MaxContainers);
+
+ LogIfrValueList (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ }
+ //
+ // Print ONE_OF_OPTION
+ //
+ PrintOneOfOptions (FormSet, Question);
+ break;
+
+ default:
+ break;
+ }
+
+ if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Prompt != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+
+ if (PrintOrNot && Question->Storage) {
+ StringPrint("// size = 0x%x", Question->StorageWidth);
+ StringPrint("\n// offset = 0x%x", Question->VarStoreInfo.VarOffset);
+ StringPrint("\n// name = ");
+ LogUnicodeString(Question->VariableName);
+ StringPrint("\n// guid = ");
+ StringPrint(
+ EFI_GUID_FORMAT,
+ Question->Guid.Data1, Question->Guid.Data2,
+ Question->Guid.Data3, Question->Guid.Data4[0],
+ Question->Guid.Data4[1],Question->Guid.Data4[2],
+ Question->Guid.Data4[3],Question->Guid.Data4[4],
+ Question->Guid.Data4[5],Question->Guid.Data4[6],
+ Question->Guid.Data4[7]
+ );
+ StringPrint("\n// attribute = 0x%x", Question->Attributes);
+ StringPrint("\n// help = ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Help,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Help != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+ }
+
+}
+
+/**
+ Check whether current Formset or Form is NULL. If no valid questions, return FASLE.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param IsFormSet FormSet or Form.
+
+ @retval TRUE
+ @return FALSE
+**/
+BOOLEAN
+CheckFormSetOrFormNull (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BOOLEAN IsFormSet
+ )
+{
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+
+ //
+ // Parse all forms in formset
+ //
+ if (IsFormSet) {
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ if (Question->Type == EFI_IFR_VARSTORE_EFI_OP
+ && Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ }
+ //
+ //If invalid variable type, skip it.
+ //
+ if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
+ && (Question->Type != EFI_IFR_VARSTORE_OP)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ return TRUE;
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ } else {
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ }
+ //
+ //If invalid variable type, skip it.
+ //
+ if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
+ && (Question->Type != EFI_IFR_VARSTORE_OP)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ return TRUE;
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Print all ONE_OF ORDER_LIST NUMERIC STRING and CHECKBOX in all fromsets.
+
+ @param Formset The pointer to the entry of the fromset list
+ @param Formset The pointer to the entry of the storage list
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+PrintInfoInAllFormset (
+ IN LIST_ENTRY *FormSetEntryListHead,
+ IN LIST_ENTRY *StorageEntryListHead
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_FORM *Form;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ FORMSET_STORAGE *Storage;
+ CHAR8 *VarBuffer;
+ LIST_ENTRY *TempStorageLink;
+ UINT32 Index;
+ BOOLEAN Skip;
+ BOOLEAN ConstantFlag;
+
+ Status = EFI_SUCCESS;
+ FormSet = NULL;
+ FormSetLink = NULL;
+ FormLink = NULL;
+ Form = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ Storage = NULL;
+ VarBuffer = NULL;
+ TempStorageLink = NULL;
+ Index = 0;
+ Skip = FALSE;
+ ConstantFlag = TRUE;
+ //
+ // Print platformId, defaultId and platformIdUqi
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ StringPrint("\n\n// FCEKEY DEFAULT_ID:");
+ TempStorageLink = GetFirstNode (StorageEntryListHead);
+ Storage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ StringPrint (" %4d", Storage->DefaultId[Index]);
+ }
+ StringPrint("\n\n//FCEKEY PLATFORM_ID:");
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ StringPrint (" %4lld", Storage->PlatformId[Index]);
+ }
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ StringPrint("\n\n//FCEKEY PLATFORM_UQI:");
+ StringPrint(" %04X ", mMultiPlatformParam.Uqi.HexNum);
+ LogUqi(mMultiPlatformParam.Uqi.Data);
+ }
+ }
+ FormSetLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ //Assign the new storage list
+ //
+ FormSet->StorageListHead = StorageEntryListHead;
+
+ if (CheckFormSetOrFormNull (FormSet, NULL, TRUE)) {
+ StringPrintormSetTitle (FormSet);
+ } else {
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ continue;
+ }
+ //
+ // Parse all forms in formset
+ //
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+
+ if (CheckFormSetOrFormNull (NULL, Form, FALSE)) {
+ StringPrintormTitle(FormSet,Form);
+ } else {
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ continue;
+ }
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_SUBTITLE_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ Skip = FALSE;
+
+ //
+ //Only output the questions stored by EFI_IFR_VARSTORE_EFI_OP.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot
+ && (Question->Operand != EFI_IFR_SUBTITLE_OP)
+ ) {
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ StorageEntryListHead,
+ (CHAR8 **)&VarBuffer,
+ &Storage
+ );
+
+ if (EFI_ERROR (Status)) {
+ Skip = TRUE;
+ }
+ }
+ //
+ // If Question is constant expression and "disabledIf True", don't output it.
+ //
+ ConstantFlag = TRUE;
+ if (!Skip && (Question->DisableExpression != NULL)) {
+ Status = EvaluateExpression (FormSet, Form, Question->DisableExpression, &ConstantFlag);
+ if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b && ConstantFlag) {
+ Skip = TRUE;
+ }
+ }
+
+ if (!Skip) {
+ PrintQuestion(FormSet, Form, Question, TRUE);
+ }
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/BaseTools/Source/C/FCE/MonotonicBasedVariable.c b/BaseTools/Source/C/FCE/MonotonicBasedVariable.c
new file mode 100644
index 0000000000..9d35bffab6
--- /dev/null
+++ b/BaseTools/Source/C/FCE/MonotonicBasedVariable.c
@@ -0,0 +1,874 @@
+/** @file
+
+ Read and edit the authenticated variables.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "MonotonicBasedVariable.h"
+
+extern LIST_ENTRY mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern G_EFI_FD_INFO gEfiFdInfo;
+EFI_GUID gEfiAuthenticatedVariableGuid = EFI_AUTHENTICATED_VARIABLE_GUID;
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+}
+
+/**
+
+ This code gets the size of variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+}
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable);
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return (UINT8 *) Value;
+}
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ if (!IsValidVariableHeader (Variable)) {
+ return NULL;
+ }
+
+ Value = (UINTN) GetVariableDataPtr (Variable);
+ Value += DataSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+ Search and get a free space in the EFI variable zone
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarListSize The size of a variables needs to be allocated.
+ @param FreeBeginVar The dual pointer to the free NV space.
+
+ @retval EFI_SUCCESS Return the beginning of a free variable space.
+ @retval RETURN_BUFFER_TOO_SMALL Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN UINT32 VarListSize,
+ IN OUT CHAR8 **FreeBeginVar
+)
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR8 *BeginVar;
+
+ BeginVar = NULL;
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ *FreeBeginVar = NULL;
+
+ if (VariableStoreHeader == NULL) {
+ *FreeBeginVar = NULL;
+ return RETURN_INVALID_PARAMETER;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ //Search the beginning of free NV
+ //
+ while (Variable != EndOfVariable) {
+ BeginVar = (CHAR8 *)Variable;
+ Variable = GetNextVariablePtr (Variable);
+ if (Variable == NULL) {
+ Flag = TRUE;
+ break;
+ }
+ }
+ //
+ // Check whether the free space is more than what we want
+ //
+ if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ //
+ // If not find the available space, return NULL
+ //
+ if (!Flag) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ *FreeBeginVar = BeginVar;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search whether the variable in VarList has existed in current NV.
+
+ Parse the FFS or Fd image, and find the valid variable pointer.
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarList The pointer to the VarList
+
+ @retval address If the variable existed in current NV, return address
+ @return NULL Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER *
+FindVariableInNv (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR16 *VariableName;
+
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ VariableName = NULL;
+
+ if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+ return NULL;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ // Parse and compare the variable in the NV space one by one
+ //
+ while ((Variable != EndOfVariable) && (Variable != NULL)) {
+ VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+ if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+ && !FceStrCmp (Storage->Name, VariableName) \
+ && (Variable->State == VAR_ADDED)) {
+ Flag = TRUE;
+ break;
+ }
+ Variable = GetNextVariablePtr (Variable);
+ }
+ if (!Flag) {
+ return NULL;
+ }
+ return Variable;
+}
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+EFI_STATUS
+SynAuthEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ CHAR8 *DataBase;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+
+ Status = EFI_SUCCESS;
+ DataBase = NULL;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if (VarToList) {
+ //
+ //Copy the data from NV to the VarList.
+ //
+ if (VariableHeader != NULL) {
+ if (Storage->Buffer == NULL) {
+ Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ ASSERT (Storage->Buffer != NULL);
+ }
+ //
+ // The variable in VarList is CHAR8, but in the EFI variable is CHAR16.
+ //
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ Storage->Buffer,
+ (VOID *) DataBase,
+ Storage->Size
+ );
+ }
+ } else {
+ //
+ //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ //
+ //If this variable has existed in current FD, the data in VarList has
+ // been updated, and this variable is not authenticated type, then
+ // update it from VarList to the FD.
+ //
+ if ((VariableHeader != NULL) \
+ && (Storage->Buffer != NULL)
+ ) {
+ if (!(VariableHeader->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)) {
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ (VOID *) DataBase,
+ Storage->Buffer,
+ Storage->Size
+ );
+ } else {
+ printf ("Error. Not support to update authenticated variables.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+ //
+ //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+ //
+ if (Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Try to get the available zone from the efi variables
+ //
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create the authenticated variable header
+ //
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ VariableHeader->PubKeyIndex = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ } else {
+ printf ("Error. No available space in NV ram.\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return Status;
+}
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+ if (VariableHeader != NULL) {
+ VariableHeader->State = VAR_DELETED;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the store variable is Monotonic based authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckMonotonicBasedVarStore (
+ IN VOID *VariableStoreHeader
+ )
+{
+ if (!CompareGuid (
+ &gEfiAuthenticatedVariableGuid,
+ &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Copy Monotonic-Based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyMonotonicBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiAuthenticatedVariableGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ VariableHeader->PubKeyIndex = 0x0;
+
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+
+
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+
+
+/**
+ Read Monotonic-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadMonotonicBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN ReadIdHeaderFlag;
+ UINT32 Length;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ static UINT64 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ ReadIdHeaderFlag = TRUE;
+ Length = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)Binary;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // If access the first storage, read the platformId and defaultId
+ //
+ if (ReadIdHeaderFlag) {
+ ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+ ReadIdHeaderFlag = FALSE;
+ memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ } else {
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ }
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ }
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+ return Length;
+}
+
+/**
+ Check whether exists the valid MonotonicBased variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistMonotonicBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if ((Storage->Buffer == NULL)
+ || (Storage->Name == NULL)
+ || (FceStrLen(Storage->Name) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if ((VariableHeader != NULL)) {
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return FALSE;
+}
+/**
+ Fix the size of montonic variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixMontonicVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+ VariableStoreHeader->Size = Length - *(UINT16 *)BinaryBeginning;
+}
diff --git a/BaseTools/Source/C/FCE/TimeBasedVariable.c b/BaseTools/Source/C/FCE/TimeBasedVariable.c
new file mode 100644
index 0000000000..e21c61dde9
--- /dev/null
+++ b/BaseTools/Source/C/FCE/TimeBasedVariable.c
@@ -0,0 +1,878 @@
+/** @file
+
+ Read and edit the time-base authenticated variables.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "TimeBasedVariable.h"
+
+extern LIST_ENTRY mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern G_EFI_FD_INFO gEfiFdInfo;
+
+EFI_GUID gEfiAuthenticatedVariableBasedTimeGuid = EFI_AUTHENTICATED_VARIABLE_BASED_TIME_GUID;
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+}
+
+/**
+
+ This code gets the size of variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+}
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable);
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return (UINT8 *) Value;
+}
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ if (!IsValidVariableHeader (Variable)) {
+ return NULL;
+ }
+
+ Value = (UINTN) GetVariableDataPtr (Variable);
+ Value += DataSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+ Search and get a free space in the EFI variable zone
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarListSize The size of a variables needs to be allocated.
+ @param FreeBeginVar The dual pointer to the free NV space.
+
+ @retval EFI_SUCCESS Return the beginning of a free variable space.
+ @retval RETURN_BUFFER_TOO_SMALL Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN UINT32 VarListSize,
+ IN OUT CHAR8 **FreeBeginVar
+)
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR8 *BeginVar;
+
+ BeginVar = NULL;
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ *FreeBeginVar = NULL;
+
+ if (VariableStoreHeader == NULL) {
+ *FreeBeginVar = NULL;
+ return RETURN_INVALID_PARAMETER;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ //Search the beginning of free NV
+ //
+ while (Variable != EndOfVariable) {
+ BeginVar = (CHAR8 *)Variable;
+ Variable = GetNextVariablePtr (Variable);
+ if (Variable == NULL) {
+ Flag = TRUE;
+ break;
+ }
+ }
+ //
+ // Check whether the free space is more than what we want
+ //
+ if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ //
+ // If not find the available space, return NULL
+ //
+ if (!Flag) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ *FreeBeginVar = BeginVar;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search whether the variable in VarList has existed in current NV.
+
+ Parse the FFS or Fd image, and find the valid variable pointer.
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarList The pointer to the VarList
+
+ @retval address If the variable existed in current NV, return address
+ @return NULL Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER *
+FindVariableInNv (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR16 *VariableName;
+
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ VariableName = NULL;
+
+ if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+ return NULL;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ // Parse and compare the variable in the NV space one by one
+ //
+ while ((Variable != EndOfVariable) && (Variable != NULL)) {
+ VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+ if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+ && !FceStrCmp (Storage->Name, VariableName) \
+ && (Variable->State == VAR_ADDED)
+ ) {
+ Flag = TRUE;
+ break;
+ }
+ Variable = GetNextVariablePtr (Variable);
+ }
+ if (!Flag) {
+ return NULL;
+ }
+ return Variable;
+}
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the time stamp authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+
+EFI_STATUS
+SynAuthEfiVariableBasedTime (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ CHAR8 *DataBase;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+
+ Status = EFI_SUCCESS;
+ DataBase = NULL;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if (VarToList) {
+ //
+ //Copy the data from NV to the VarList.
+ //
+ if (VariableHeader != NULL) {
+ if (Storage->Buffer == NULL) {
+ Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ ASSERT (Storage->Buffer != NULL);
+ }
+ //
+ // The variable in VarList is CHAR8, but in the EFI variable is CHAR16.
+ //
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ Storage->Buffer,
+ (VOID *) DataBase,
+ Storage->Size
+ );
+ }
+ } else {
+ //
+ //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ //
+ //If this variable has existed in current FD, the data in VarList has
+ // been updated, and this variable is not authenticated type, then
+ // update it from VarList to the FD.
+ //
+ if ((VariableHeader != NULL) \
+ && (Storage->Buffer != NULL)
+ ) {
+ if (!(VariableHeader->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)) {
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ (VOID *) DataBase,
+ Storage->Buffer,
+ Storage->Size
+ );
+ } else {
+ printf ("Error. Not support to update authenticated variables.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+ //
+ //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+ //
+ if (Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Try to get the available zone from the efi variables
+ //
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create the authenticated variable header
+ //
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ memset (&(VariableHeader->TimeStamp), 0, sizeof (EFI_TIME));
+ VariableHeader->PubKeyIndex = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ } else {
+ printf ("Error. No available space in NV ram.\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return Status;
+}
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariableBasedTime (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+ if (VariableHeader != NULL) {
+ VariableHeader->State = VAR_DELETED;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the store variable is Time stamp authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckTimeBasedVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ )
+{
+ if (!CompareGuid (
+ &gEfiAuthenticatedVariableBasedTimeGuid,
+ &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Copy time-based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyTimeBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiAuthenticatedVariableBasedTimeGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ memset (&(VariableHeader->TimeStamp), 0, sizeof (EFI_TIME));
+ VariableHeader->PubKeyIndex = 0x0;
+
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+
+/**
+ Read time-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadTimeBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN ReadIdHeaderFlag;
+ UINT32 Length;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ static UINT64 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ ReadIdHeaderFlag = TRUE;
+ Length = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)Binary;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // If access the first storage, read the platformId and defaultId
+ //
+ if (ReadIdHeaderFlag) {
+ ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+ ReadIdHeaderFlag = FALSE;
+ memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ } else {
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ }
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ }
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+ return Length;
+}
+
+/**
+ Check whether exists the valid time-based variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistTimeBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if ((Storage->Buffer == NULL)
+ || (Storage->Name == NULL)
+ || (FceStrLen(Storage->Name) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if ((VariableHeader != NULL)) {
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return FALSE;
+}
+
+/**
+ Fix the size of time-based variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixBasedTimeVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+ VariableStoreHeader->Size = Length - *(UINT16 *)BinaryBeginning;
+}
diff --git a/BaseTools/Source/C/FCE/Variable.c b/BaseTools/Source/C/FCE/Variable.c
new file mode 100644
index 0000000000..5c92060309
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Variable.c
@@ -0,0 +1,1091 @@
+/** @file
+
+ Read and edit the EFI variable.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "Variable.h"
+
+extern LIST_ENTRY mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern G_EFI_FD_INFO gEfiFdInfo;
+
+EFI_GUID gEfiVariableGuid = EFI_VARIABLE_GUID;
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+}
+
+/**
+
+ This code gets the size of variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+}
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+
+ return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable);
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return (UINT8 *) Value;
+}
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ if (!IsValidVariableHeader (Variable)) {
+ return NULL;
+ }
+
+ Value = (UINTN) GetVariableDataPtr (Variable);
+ Value += DataSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+ Search and get a free space in the EFI variable zone
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarListSize The size of a variables needs to be allocated.
+ @param FreeBeginVar The dual pointer to the free NV space.
+
+ @retval EFI_SUCCESS Return the beginning of a free variable space.
+ @retval RETURN_BUFFER_TOO_SMALL Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN UINT32 VarListSize,
+ IN OUT CHAR8 **FreeBeginVar
+)
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR8 *BeginVar;
+
+ BeginVar = NULL;
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ *FreeBeginVar = NULL;
+
+ if (VariableStoreHeader == NULL) {
+ *FreeBeginVar = NULL;
+ return RETURN_INVALID_PARAMETER;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ //Search the beginning of free NV
+ //
+ while (Variable != EndOfVariable) {
+ BeginVar = (CHAR8 *)Variable;
+ Variable = GetNextVariablePtr (Variable);
+ if (Variable == NULL) {
+ Flag = TRUE;
+ break;
+ }
+ }
+ //
+ // Check whether the free space is more than what we want
+ //
+ if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ //
+ // If not find the available space, return NULL
+ //
+ if (!Flag) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ *FreeBeginVar = BeginVar;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search whether the variable in VarList has existed in current NV.
+
+ Parse the FFS or Fd image, and find the valid variable pointer.
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarList The pointer to the VarList
+
+ @retval address If the variable existed in current NV, return address
+ @return NULL Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER *
+FindVariableInNv (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR16 *VariableName;
+
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ VariableName = NULL;
+
+ if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+ return NULL;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ // Parse and compare the variable in the NV space one by one
+ //
+ while ((Variable != EndOfVariable) && (Variable != NULL)) {
+ VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+ if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+ && !FceStrCmp (Storage->Name, VariableName) \
+ && (Variable->State == VAR_ADDED)) {
+ Flag = TRUE;
+ break;
+ }
+ Variable = GetNextVariablePtr (Variable);
+ }
+ if (!Flag) {
+ return NULL;
+ }
+ return Variable;
+}
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+**/
+
+EFI_STATUS
+SynEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ CHAR8 *DataBase;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+
+ Status = EFI_SUCCESS;
+ DataBase = NULL;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if (VarToList) {
+ //
+ //Copy the data from NV to the VarList.
+ //
+ if (VariableHeader != NULL) {
+ if (Storage->Buffer == NULL) {
+ Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ ASSERT (Storage->Buffer != NULL);
+ }
+ DataBase = (CHAR8*)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ Storage->Buffer,
+ (VOID *) DataBase,
+ Storage->Size
+ );
+ }
+ } else {
+ //
+ //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ //
+ //If this variable has existed in current FD, the data in VarList has
+ // been updated, and this variable is not authenticated type, then
+ // update it from VarList to the FD.
+ //
+ if ((VariableHeader != NULL) \
+ && (Storage->Buffer != NULL)
+ ) {
+ DataBase = (CHAR8*)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ (VOID *) DataBase,
+ Storage->Buffer,
+ Storage->Size
+ );
+ } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+ //
+ //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+ //
+ if (Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Try to get the available zone from the efi variables
+ //
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create the variable header
+ //
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ } else {
+ printf ("Error. No available space in NV ram.\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return Status;
+}
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveNormalEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+ if (VariableHeader != NULL) {
+ VariableHeader->State = VAR_DELETED;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the store variable is no-authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If no-authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckNormalVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ )
+{
+ if (!CompareGuid (
+ &gEfiVariableGuid,
+ &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiVariableGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToNvStoreBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+ PCD_DEFAULT_DATA *PcdDefaultDataHeader;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteNvStoreDefaultAndPlatformId (StorageBeginning, Storage);
+ PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)StorageBeginning;
+ PcdDefaultDataHeader->HeaderSize = HeaderLength;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength + 4);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiVariableGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+ PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)StorageBeginning;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + PcdDefaultDataHeader->HeaderSize + 4);
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning - PcdDefaultDataHeader->HeaderSize - 4) + Storage->Size);
+}
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadNvStoreVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ UINT32 Length;
+ PCD_DEFAULT_DATA *PcdDefaultData;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId;
+ static UINT64 PrePlatformId;
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ Length = 0;
+ DataBase = Binary;
+
+ PcdDefaultData = (PCD_DEFAULT_DATA *)DataBase;
+ PrePlatformId = PcdDefaultData->DefaultInfo[0].SkuId;
+ PreDefaultId = PcdDefaultData->DefaultInfo[0].DefaultId;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + PcdDefaultData->HeaderSize + 4);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ Storage->DefaultId[0] = PreDefaultId;
+ Storage->PlatformId[0] = PrePlatformId;
+ Storage->DefaultPlatformIdNum = 0;
+
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ if (!IsValidVariableHeader(Variable)) {
+ break;
+ }
+ }
+
+ return Length;
+}
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN ReadIdHeaderFlag;
+ UINT32 Length;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ static UINT64 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ ReadIdHeaderFlag = TRUE;
+ Length = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)Binary;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // If access the first storage, read the platformId and defaultId
+ //
+ if (ReadIdHeaderFlag) {
+ ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+ ReadIdHeaderFlag = FALSE;
+ memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ } else {
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ }
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ }
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+ return Length;
+}
+
+/**
+ Check whether exists the valid normal variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistNormalEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if ((Storage->Buffer == NULL)
+ || (Storage->Name == NULL)
+ || (FceStrLen(Storage->Name) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if ((VariableHeader != NULL)) {
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return FALSE;
+}
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+ VariableStoreHeader->Size = Length - *(UINT16 *)BinaryBeginning;
+}
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixNvStoreVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ PCD_DEFAULT_DATA *PcdDefaultDataHeader;
+
+ PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)(BinaryBeginning);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + PcdDefaultDataHeader->HeaderSize + 4);
+ VariableStoreHeader->Size = Length;
+ PcdDefaultDataHeader->DataSize = VariableStoreHeader->Size + PcdDefaultDataHeader->HeaderSize + 4;
+}
+
diff --git a/BaseTools/BinWrappers/PosixLike/FCE b/BaseTools/BinWrappers/PosixLike/FCE
new file mode 100755
index 0000000000..a244ecc095
--- /dev/null
+++ b/BaseTools/BinWrappers/PosixLike/FCE
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
+dir=$(dirname "$full_cmd")
+cmd=${full_cmd##*/}
+
+if [ -n "$WORKSPACE" ] && [ -e "$WORKSPACE/Conf/BaseToolsCBinaries" ]
+then
+ exec "$WORKSPACE/Conf/BaseToolsCBinaries/$cmd"
+elif [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/Source/C" ]
+then
+ if [ ! -e "$EDK_TOOLS_PATH/Source/C/bin/$cmd" ]
+ then
+ echo "BaseTools C Tool binary was not found ($cmd)"
+ echo "You may need to run:"
+ echo " make -C $EDK_TOOLS_PATH/Source/C"
+ else
+ exec "$EDK_TOOLS_PATH/Source/C/bin/$cmd" "$@"
+ fi
+elif [ -e "$dir/../../Source/C/bin/$cmd" ]
+then
+ exec "$dir/../../Source/C/bin/$cmd" "$@"
+else
+ echo "Unable to find the real '$cmd' to run"
+ echo "This message was printed by"
+ echo " $0"
+ exit 127
+fi
+
diff --git a/BaseTools/Source/C/FCE/BinaryCreate.h b/BaseTools/Source/C/FCE/BinaryCreate.h
new file mode 100644
index 0000000000..0e2f22599e
--- /dev/null
+++ b/BaseTools/Source/C/FCE/BinaryCreate.h
@@ -0,0 +1,157 @@
+/** @file
+
+ The API to create the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BINARY_CREATE_H_
+#define _BINARY_CREATE_H_ 1
+
+#include <FvLib.h>
+#include "Compress.h"
+#include "Decompress.h"
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "FirmwareVolumeBufferLib.h"
+#include "OsPath.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "ParseInf.h"
+#include <Common/UefiBaseTypes.h>
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/UefiCapsule.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include <IndustryStandard/PeImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+//1AE42876-008F-4161-B2B7-1C0D15C5EF43
+#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID \
+ { 0x1ae42876, 0x008f, 0x4161, { 0xb2, 0xb7, 0x1c, 0xd, 0x15, 0xc5, 0xef, 0x43 }}
+
+extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid;
+
+// {003E7B41-98A2-4BE2-B27A-6C30C7655225}
+#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID2 \
+ { 0x3e7b41, 0x98a2, 0x4be2, { 0xb2, 0x7a, 0x6c, 0x30, 0xc7, 0x65, 0x52, 0x25 }}
+
+extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid2;
+
+typedef UINT64 SKU_ID;
+
+typedef struct {
+ UINT32 Offset:24;
+ UINT32 Value:8;
+} PCD_DATA_DELTA;
+
+typedef struct {
+ SKU_ID SkuId;
+ UINT16 DefaultId;
+ UINT8 Reserved[6];
+} PCD_DEFAULT_INFO;
+
+typedef struct {
+ //
+ // Full size, it must be at 8 byte alignment.
+ //
+ UINT32 DataSize;
+ //
+ // HeaderSize includes HeaderSize fields and DefaultInfo arrays
+ //
+ UINT32 HeaderSize;
+ //
+ // DefaultInfo arrays those have the same default setting.
+ //
+ PCD_DEFAULT_INFO DefaultInfo[1];
+ //
+ // Default data is stored as variable storage or the array of DATA_DELTA.
+ //
+} PCD_DEFAULT_DATA;
+
+#define PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE SIGNATURE_32('N', 'S', 'D', 'B')
+
+typedef struct {
+ //
+ // PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE
+ //
+ UINT32 Signature;
+ //
+ // Length of the taken default buffer
+ //
+ UINT32 Length;
+ //
+ // Length of the total reserved buffer
+ //
+ UINT32 MaxLength;
+ //
+ // Reserved for 8 byte alignment
+ //
+ UINT32 Reserved;
+ // one or more PCD_DEFAULT_DATA
+} PCD_NV_STORE_DEFAULT_BUFFER_HEADER;
+
+//
+// NvStoreDefaultValueBuffer layout:
+// +-------------------------------------+
+// | PCD_NV_STORE_DEFAULT_BUFFER_HEADER |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (DEFAULT, Standard)|
+// +-------------------------------------+
+// | PCD_DATA_DELTA (DEFAULT, Standard)|
+// +-------------------------------------+
+// | ...... |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (SKU A, Standard) |
+// +-------------------------------------+
+// | PCD_DATA_DELTA (SKU A, Standard) |
+// +-------------------------------------+
+// | ...... |
+// +-------------------------------------+
+//
+
+#pragma pack(1)
+
+typedef struct {
+ UINT16 Offset;
+ UINT8 Value;
+} DATA_DELTA;
+
+#pragma pack()
+
+/**
+ Create the Ras section in FFS
+
+ @param[in] InputFilePath The input file path and name.
+ @param[in] OutputFilePath The output file path and name.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawSection (
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath
+ );
+
+/**
+ Create the Ras type of FFS
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] OutputFilePath .te or .pe file
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawFfs (
+ IN CHAR8** InputFilePaths,
+ IN CHAR8* OutputFilePath,
+ IN BOOLEAN SizeOptimized
+ );
+
+#endif
+
diff --git a/BaseTools/Source/C/FCE/BinaryParse.h b/BaseTools/Source/C/FCE/BinaryParse.h
new file mode 100644
index 0000000000..a3995b8b79
--- /dev/null
+++ b/BaseTools/Source/C/FCE/BinaryParse.h
@@ -0,0 +1,187 @@
+/** @file
+
+ The API to parse the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _BINARY_PARSE_H_
+#define _BINARY_PARSE_H_ 1
+
+#include <FvLib.h>
+#include "Compress.h"
+#include "Decompress.h"
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "FirmwareVolumeBufferLib.h"
+#include "OsPath.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "ParseInf.h"
+#include <Common/UefiBaseTypes.h>
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/UefiCapsule.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include <IndustryStandard/PeImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+#ifdef __GNUC__
+#define OS_SEP '/'
+#define OS_SEP_STR "/"
+#else
+#define OS_SEP '\\'
+#define OS_SEP_STR "\\"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#define TEMP_DIR_NAME "Temp"
+#define MAX_FILENAME_LEN 200
+#define MAX_MATCH_GUID_NUM 100
+#define MAX_EFI_IN_FFS_NUM 100
+
+typedef struct {
+ VOID *Fd;
+ UINT32 FdSize;
+ UINTN EfiVariableAddr;
+ UINTN Length[MAX_EFI_IN_FFS_NUM];
+ VOID *FfsArray[MAX_EFI_IN_FFS_NUM];
+ VOID *StorageFfsInBfv;
+ VOID *NvStoreDatabase;
+ BOOLEAN ExistNvStoreDatabase;
+} G_EFI_FD_INFO;
+
+///
+///Define the structure for th sections
+///
+typedef struct {
+ UINTN BufferBase;
+ UINTN UncompressedBuffer[MAX_EFI_IN_FFS_NUM];
+ UINTN Length;
+ UINT8 UnCompressIndex;
+} EFI_SECTION_STRUCT;
+
+// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
+#define EFI_VFR_ATTRACT_GUID \
+{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }
+
+// {8913C5E0-33F6-4d86-9BF1-43EF89FC0666}
+#define EFI_UNI_STR_ATTRACT_GUID \
+{ 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
+
+// {FFF12B8D-7696-4C8B-A985-2747075B4F50}
+#define EFI_SYSTEM_NVDATA_FV_GUID \
+{ 0xFFF12B8D, 0x7696, 0x4C8B, { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+
+/**
+ Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS.
+
+ @param SectionBuffer The section base address
+ @param BufferLength The length of FFS.
+ @param EfiBufferHeader The structure dual pointer to the efi informations
+
+ @retval EFI_SUCCESS The application exited normally.
+ @retval EFI_ABORTED An error occurred.
+
+**/
+EFI_STATUS
+ParseSection (
+ IN BOOLEAN IsFfsOrEfi,
+ IN OUT UINT8 *SectionBuffer,
+ IN UINT32 BufferLength,
+ IN OUT EFI_SECTION_STRUCT **EfiBufferHeader
+ );
+
+/**
+ Search the VfrBin Base address.
+
+ According the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+ @param NumOfMachingOffset the number of Addr (Offset)
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+SearchVfrBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMachingOffset
+ );
+
+/**
+ Search the UniBin Base address.
+
+ According the known GUID gUniStrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+
+ @retval Base address Get the address successfully.
+**/
+EFI_STATUS
+SearchUniBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset
+ );
+
+/**
+ Read the file to memory.
+
+ @param InputFile The file that contains the FV image.
+ @param Size The size of the file.
+
+ @retval The pointer to the begining position of memory.
+**/
+VOID *
+ReadFileToMemory (
+ IN CHAR8 *FileName,
+ OUT UINT32 *Size
+ );
+
+/**
+ Search the EFI variables address in Fd.
+
+ Open and read the *.fd to the memory, initialize the global structure.
+ Update the EFI variables addr and the begining position of memory.
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+GetEfiVariablesAddr (
+ BOOLEAN UqiIsSet
+ );
+
+/**
+ Pick up the FFS which includes IFR section.
+
+ Parse all FFS extracted by BfmLib, and save all which includes IFR
+ Binary to gEfiFdInfo structure.
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated.
+ @retval EFI_ABORTED Read FFS Failed.
+**/
+EFI_STATUS
+FindFileInFolder (
+ IN CHAR8 *FolderName,
+ OUT BOOLEAN *ExistStorageInBfv,
+ OUT BOOLEAN *SizeOptimized
+);
+
+#endif
+
diff --git a/BaseTools/Source/C/FCE/Common.h b/BaseTools/Source/C/FCE/Common.h
new file mode 100644
index 0000000000..6b21974878
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Common.h
@@ -0,0 +1,999 @@
+/** @file
+
+ Common library.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _COMMON_LIB_H_
+#define _COMMON_LIB_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+#include "CommonLib.h"
+#include <Common/UefiBaseTypes.h>
+
+#define MAX_QUI_PARAM_LEN 2000
+#define ERROR_INFO_LENGTH 400
+#define MAX_STR_LEN_FOR_PICK_UQI 200
+#define MAX_PLATFORM_DEFAULT_ID_NUM 1000
+#define _MAX_BUILD_VERSION 100
+#define _MAXIMUM_SECTION_FILE_NUM 1000
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+///
+/// Variable attributes.
+///
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+
+///
+/// This attribute is identified by the mnemonic 'HR'
+/// elsewhere in this specification.
+///
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
+
+#define VARSTORE_LIST_TYPE 0x0000000000000001ULL
+#define EFI_VARSTORE_LIST_TYPE 0x0000000000000002ULL
+#define PLATFORM_DEFAULT_ID_TYPE 0x0000000000000004ULL
+#define UQI_LIST_TYPE 0x0000000000000008ULL
+#define HII_OBJ_LIST_TYPE 0x0000000000000010ULL
+
+///
+/// LIST_ENTRY structure definition.
+///
+typedef struct _LIST_ENTRY {
+ struct _LIST_ENTRY *ForwardLink;
+ struct _LIST_ENTRY *BackLink;
+} LIST_ENTRY;
+
+#define CR(Record, TYPE, Field, TestSignature) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))
+#define AllocateZeroPool(a) calloc(a, sizeof (CHAR8))
+#define FreePool(a) free(a)
+#define CopyMem(a, b, c) memcpy(a, b, c)
+#define ZeroMem(a, b) memset(a, 0, b)
+#define CompareMem(a, b, c) memcmp(a, b, c)
+#define AllocatePool(a) malloc(a)
+
+/**
+ Returns a 16-bit signature built from 2 ASCII characters.
+
+ This macro returns a 16-bit value built from the two ASCII characters specified
+ by A and B.
+
+ @param A The first ASCII character.
+ @param B The second ASCII character.
+
+ @return A 16-bit value built from the two ASCII characters specified by A and B.
+
+**/
+#define SIGNATURE_16(A, B) ((A) | (B << 8))
+
+/**
+ Returns a 32-bit signature built from 4 ASCII characters.
+
+ This macro returns a 32-bit value built from the four ASCII characters specified
+ by A, B, C, and D.
+
+ @param A The first ASCII character.
+ @param B The second ASCII character.
+ @param C The third ASCII character.
+ @param D The fourth ASCII character.
+
+ @return A 32-bit value built from the two ASCII characters specified by A, B,
+ C and D.
+
+**/
+#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
+
+#define ASSERT_UNICODE_BUFFER(Buffer) ASSERT ((((UINTN) (Buffer)) & 0x01) == 0)
+
+/**
+ Returns an argument of a specified type from a variable argument list and updates
+ the pointer to the variable argument list to point to the next argument.
+
+ This function returns an argument of the type specified by TYPE from the beginning
+ of the variable argument list specified by Marker. Marker is then updated to point
+ to the next argument in the variable argument list. The method for computing the
+ pointer to the next argument in the argument list is CPU specific following the EFIAPI ABI.
+
+ @param Marker The pointer to the beginning of a variable argument list.
+ @param TYPE The type of argument to retrieve from the beginning
+ of the variable argument list.
+
+ @return An argument of the type specified by TYPE.
+
+**/
+#define BASE_ARG(Marker, TYPE) (*(TYPE *) ((Marker += _BASE_INT_SIZE_OF (TYPE)) - _BASE_INT_SIZE_OF (TYPE)))
+
+///
+/// Define the maximum number of characters that are required to
+/// encode with a NULL terminator a decimal, hexadecimal, GUID,
+/// or TIME value.
+///
+/// Maximum Length Decimal String = 28
+/// "-9,223,372,036,854,775,808"
+/// Maximum Length Hexadecimal String = 17
+/// "FFFFFFFFFFFFFFFF"
+/// Maximum Length GUID = 37
+/// "00000000-0000-0000-0000-000000000000"
+/// Maximum Length TIME = 18
+/// "12/12/2006 12:12"
+///
+#define MAXIMUM_VALUE_CHARACTERS 38
+
+///
+/// Pointer to the start of a variable argument list stored in a memory buffer. Same as UINT8 *.
+///
+typedef UINTN *BASE_LIST;
+
+/**
+ Returns the size of a data type in sizeof(UINTN) units rounded up to the nearest UINTN boundary.
+
+ @param TYPE The date type to determine the size of.
+
+ @return The size of TYPE in sizeof (UINTN) units rounded up to the nearest UINTN boundary.
+**/
+#define _BASE_INT_SIZE_OF(TYPE) ((sizeof (TYPE) + sizeof (UINTN) - 1) / sizeof (UINTN))
+
+//
+// Print primitives
+//
+#define PREFIX_SIGN BIT1
+#define PREFIX_BLANK BIT2
+#define LONG_TYPE BIT4
+#define OUTPUT_UNICODE BIT6
+#define FORMAT_UNICODE BIT8
+#define PAD_TO_WIDTH BIT9
+#define ARGUMENT_UNICODE BIT10
+#define PRECISION BIT11
+#define ARGUMENT_REVERSED BIT12
+#define COUNT_ONLY_NO_PRINT BIT13
+
+///
+/// Flags bitmask values use in UnicodeValueToString() and
+/// AsciiValueToString()
+///
+#define LEFT_JUSTIFY 0x01
+#define COMMA_TYPE 0x08
+#define PREFIX_ZERO 0x20
+#define RADIX_HEX 0x80
+
+//
+// Record date and time information
+//
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Pad1;
+ UINT32 Nanosecond;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINT8 Pad2;
+} TIME;
+
+
+/**
+ Copies one Null-terminated Unicode string to another Null-terminated Unicode
+ string and returns the new Unicode string.
+
+ This function copies the contents of the Unicode string Source to the Unicode
+ string Destination, and returns Destination. If Source and Destination
+ overlap, then the results are undefined.
+
+ If Destination is NULL, then return NULL.
+ If Destination is not aligned on a 16-bit boundary, then return NULL.
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCpy (
+ OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ );
+
+/**
+ Returns the length of a Null-terminated Unicode string.
+
+ This function returns the number of Unicode characters in the Null-terminated
+ Unicode string specified by String.
+
+ If String is NULL, then return 0.
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The length of String.
+
+**/
+UINTN
+FceStrLen (
+ IN CONST CHAR16 *String
+ );
+
+/**
+ Returns the size of a Null-terminated Unicode string in bytes, including the
+ Null terminator.
+
+ This function returns the size, in bytes, of the Null-terminated Unicode string
+ specified by String.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The size of String.
+
+**/
+UINTN
+FceStrSize (
+ IN CONST CHAR16 *String
+ );
+
+/**
+ Compares two Null-terminated Unicode strings, and returns the difference
+ between the first mismatched Unicode characters.
+
+ This function compares the Null-terminated Unicode string FirstString to the
+ Null-terminated Unicode string SecondString. If FirstString is identical to
+ SecondString, then 0 is returned. Otherwise, the value returned is the first
+ mismatched Unicode character in SecondString subtracted from the first
+ mismatched Unicode character in FirstString.
+
+ @param FirstString A pointer to a Null-terminated Unicode string.
+ @param SecondString A pointer to a Null-terminated Unicode string.
+
+ @retval 0 FirstString is identical to SecondString.
+ @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+FceStrCmp (
+ IN CONST CHAR16 *FirstString,
+ IN CONST CHAR16 *SecondString
+ );
+
+/**
+ Concatenates one Null-terminated Unicode string to another Null-terminated
+ Unicode string, and returns the concatenated Unicode string.
+
+ This function concatenates two Null-terminated Unicode strings. The contents
+ of Null-terminated Unicode string Source are concatenated to the end of
+ Null-terminated Unicode string Destination. The Null-terminated concatenated
+ Unicode String is returned. If Source and Destination overlap, then the
+ results are undefined.
+
+ If Destination is NULL, then ASSERT().
+ If Destination is not aligned on a 16-bit boundary, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+ than PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+ and Source results in a Unicode string with more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCat (
+ IN OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ );
+
+/**
+ Returns the first occurrence of a Null-terminated Unicode sub-string
+ in a Null-terminated Unicode string.
+
+ This function scans the contents of the Null-terminated Unicode string
+ specified by String and returns the first occurrence of SearchString.
+ If SearchString is not found in String, then NULL is returned. If
+ the length of SearchString is zero, then String is
+ returned.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If SearchString is NULL, then ASSERT().
+ If SearchString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and SearchString
+ or String contains more than PcdMaximumUnicodeStringLength Unicode
+ characters, not including the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+ @param SearchString A pointer to a Null-terminated Unicode string to search for.
+
+ @retval NULL If the SearchString does not appear in String.
+ @return others If there is a match.
+
+**/
+CHAR16 *
+StrStr (
+ IN CONST CHAR16 *String,
+ IN CONST CHAR16 *SearchString
+ );
+
+/**
+ Convert a Null-terminated Unicode decimal string to a value of
+ type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a decimal number. The format
+ of the input Unicode string String is:
+
+ [spaces] [decimal digits].
+
+ The valid decimal digit character is in the range [0-9]. The
+ function will ignore the pad space, which includes spaces or
+ tab characters, before [decimal digits]. The running zero in the
+ beginning of [decimal digits] will be ignored. Then, the function
+ stops at the first character that is a not a valid decimal character
+ or a Null-terminator, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then 0 is returned.
+ If String has no pad spaces or valid decimal digits,
+ then 0 is returned.
+ If the number represented by String overflows according
+ to the range defined by UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains
+ more than PcdMaximumUnicodeStringLength Unicode characters, not including
+ the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrDecimalToUint64 (
+ IN CONST CHAR16 *String
+ );
+
+
+/**
+ Convert one Null-terminated ASCII string to a Null-terminated
+ Unicode string and returns the Unicode string.
+
+ This function converts the contents of the ASCII string Source to the Unicode
+ string Destination, and returns Destination. The function terminates the
+ Unicode string Destination by appending a Null-terminator character at the end.
+ The caller is responsible to make sure Destination points to a buffer with size
+ equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
+
+ @param Source A pointer to a Null-terminated ASCII string.
+ @param Destination A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+ @return NULL If Destination or Source is NULL, return NULL.
+
+**/
+CHAR16 *
+AsciiStrToUnicodeStr (
+ IN CONST CHAR8 *Source,
+ OUT CHAR16 *Destination
+ );
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and variable argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine
+
+ @param StartOfBuffer The character buffer to print the results of the parsing
+ of Format into.
+ @param BufferSize The maximum number of characters to put into buffer.
+ Zero means no limit.
+ @param Flags Initial flags value.
+ Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+ @param FormatString A Null-terminated format string.
+ @param ... The variable argument list.
+
+ @return The number of characters printed.
+
+**/
+UINTN
+BasePrintLibSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+UnicodeSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ );
+
+/**
+ Convert a Null-terminated Unicode string to a Null-terminated
+ ASCII string and returns the ASCII string.
+
+ This function converts the content of the Unicode string Source
+ to the ASCII string Destination by copying the lower 8 bits of
+ each Unicode character. It returns Destination. The function terminates
+ the ASCII string Destination by appending a Null-terminator character
+ at the end. The caller is responsible to make sure Destination points
+ to a buffer with size equal or greater than (FceStrLen (Source) + 1) in bytes.
+
+ If Destination is NULL, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+
+ If any Unicode characters in Source contain non-zero value in
+ the upper 8 bits, then ASSERT().
+
+ @param Source Pointer to a Null-terminated Unicode string.
+ @param Destination Pointer to a Null-terminated ASCII string.
+
+ @reture Destination
+
+**/
+CHAR8 *
+UnicodeStrToAsciiStr (
+ IN CONST CHAR16 *Source,
+ OUT CHAR8 *Destination
+ );
+
+/**
+ Allocate new memory and then copy the Unicode string Source to Destination.
+
+ @param Dest Location to copy string
+ @param Src String to copy
+
+**/
+VOID
+NewStringCpy (
+ IN OUT CHAR16 **Dest,
+ IN CHAR16 *Src
+ );
+
+/**
+ Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a hexadecimal number.
+ The format of the input Unicode string String is
+
+ [spaces][zeros][x][hexadecimal digits].
+
+ The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+ The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+ If "x" appears in the input string, it must be prefixed with at least one 0.
+ The function will ignore the pad space, which includes spaces or tab characters,
+ before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+ [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+ first valid hexadecimal digit. Then, the function stops at the first character that is
+ a not a valid hexadecimal character or NULL, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then zero is returned.
+ If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+ then zero is returned.
+ If the number represented by String overflows according to the range defined by
+ UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+ then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrHexToUint64 (
+ IN CONST CHAR16 *String
+ );
+
+
+CHAR16
+ToUpper (
+ CHAR16 a
+ );
+
+CHAR16
+ToLower (
+ CHAR16 a
+ );
+
+/**
+ Performs a case-insensitive comparison between a Null-terminated
+ Unicode pattern string and a Null-terminated Unicode string.
+
+ @param String - A pointer to a Null-terminated Unicode string.
+ @param Pattern - A pointer to a Null-terminated Unicode pattern string.
+
+
+ @retval TRUE - Pattern was found in String.
+ @retval FALSE - Pattern was not found in String.
+
+**/
+BOOLEAN
+MetaiMatch (
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ );
+
+/**
+ Multiplies a 64-bit unsigned integer by a 32-bit unsigned integer and
+ generates a 64-bit unsigned result.
+
+ This function multiplies the 64-bit unsigned value Multiplicand by the 32-bit
+ unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+ bit unsigned result is returned.
+
+ @param Multiplicand A 64-bit unsigned value.
+ @param Multiplier A 32-bit unsigned value.
+
+ @return Multiplicand * Multiplier.
+
+**/
+UINT64
+MultU64x32 (
+ IN UINT64 Multiplicand,
+ IN UINT32 Multiplier
+ );
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. This
+ function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32 (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor
+ );
+
+/**
+ Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
+ with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the left by Count bits. The
+ low Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift left.
+ @param Count The number of bits to shift left.
+
+ @return Operand << Count.
+
+**/
+UINT64
+LShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ );
+
+/**
+ Shifts a 64-bit integer right between 0 and 63 bits. This high bits are
+ filled with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the right by Count bits. The
+ high Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift right.
+ @param Count The number of bits to shift right.
+
+ @return Operand >> Count.
+
+**/
+UINT64
+RShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ );
+
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result and an optional 32-bit unsigned remainder.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+ is not NULL, then the 32-bit unsigned remainder is returned in Remainder.
+ This function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+ @param Remainder A pointer to a 32-bit unsigned value. This parameter is
+ optional and may be NULL.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32Remainder (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor,
+ OUT UINT32 *Remainder
+ );
+
+/**
+ Copies a buffer to an allocated buffer.
+
+ Allocates the number bytes specified by AllocationSize, copies allocationSize bytes
+ from Buffer to the newly allocated buffer, 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.
+
+ If Buffer is NULL, then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+FceAllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ );
+
+/**
+ Initializes the head node of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Initializes the forward and backward links of a new linked list. After
+ initializing a linked list with this function, the other linked list
+ functions may be used to add and remove nodes from the linked list. It is up
+ to the caller of this function to allocate the memory for ListHead.
+
+ If ListHead is NULL, then ASSERT().
+
+ @param ListHead A pointer to the head node of a new doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InitializeListHead (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Adds a node to the beginning of a doubly-linked list, and returns the pointer
+ to the head node of the doubly-linked list.
+
+ Adds the node Entry at the beginning of the doubly-linked list denoted by
+ ListHead, and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be inserted at the beginning
+ of a doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertHeadList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ );
+
+/**
+ Adds a node to the end of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Adds the node Entry to the end of the doubly-linked list denoted by ListHead,
+ and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be added at the end of the
+ doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertTailList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ );
+
+/**
+ Retrieves the first node of a doubly-linked list.
+
+ Returns the first node of a doubly-linked list. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+ If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+
+ @return The first node of a doubly-linked list.
+ @retval NULL The list is empty.
+
+**/
+LIST_ENTRY *
+GetFirstNode (
+ IN CONST LIST_ENTRY *List
+ );
+
+/**
+ Retrieves the next node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that follows Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the next node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetNextNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Retrieves the previous node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that precedes Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the previous node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetPreviousNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Checks to see if a doubly-linked list is empty or not.
+
+ Checks to see if the doubly-linked list is empty. If the linked list contains
+ zero nodes, this function returns TRUE. Otherwise, it returns FALSE.
+
+ If ListHead is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+
+ @retval TRUE The linked list is empty.
+ @retval FALSE The linked list is not empty.
+
+**/
+BOOLEAN
+IsListEmpty (
+ IN CONST LIST_ENTRY *ListHead
+ );
+
+/**
+ Determines if a node in a doubly-linked list is the head node of a the same
+ doubly-linked list. This function is typically used to terminate a loop that
+ traverses all the nodes in a doubly-linked list starting with the head node.
+
+ Returns TRUE if Node is equal to List. Returns FALSE if Node is one of the
+ nodes in the doubly-linked list specified by List. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),
+ then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List and Node is not
+ equal to List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the head of the doubly-linked list pointed by List.
+ @retval FALSE Node is not the head of the doubly-linked list pointed by List.
+
+**/
+BOOLEAN
+IsNull (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Determines if a node the last node in a doubly-linked list.
+
+ Returns TRUE if Node is the last node in the doubly-linked list specified by
+ List. Otherwise, FALSE is returned. List must have been initialized with
+ INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the last node in the linked list.
+ @retval FALSE Node is not the last node in the linked list.
+
+**/
+BOOLEAN
+IsNodeAtEnd (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Removes a node from a doubly-linked list, and returns the node that follows
+ the removed node.
+
+ Removes the node Entry from a doubly-linked list. It is up to the caller of
+ this function to release the memory used by this node if that is required. On
+ exit, the node following Entry in the doubly-linked list is returned. If
+ Entry is the only node in the linked list, then the head node of the linked
+ list is returned.
+
+ If Entry is NULL, then ASSERT().
+ If Entry is the head node of an empty list, then ASSERT().
+ If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+ linked list containing Entry, including the Entry node, is greater than
+ or equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param Entry A pointer to a node in a linked list.
+
+ @return Entry.
+
+**/
+LIST_ENTRY *
+RemoveEntryList (
+ IN CONST LIST_ENTRY *Entry
+ );
+
+#endif
diff --git a/BaseTools/Source/C/FCE/Fce.h b/BaseTools/Source/C/FCE/Fce.h
new file mode 100644
index 0000000000..32cc3a1ccc
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Fce.h
@@ -0,0 +1,447 @@
+/** @file
+
+ FCE is a tool which enables developers to retrieve and change HII configuration ("Setup")
+ data in Firmware Device files (".fd" files).
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FCE_H_
+#define _FCE_H_ 1
+
+//#define NDEBUG
+
+#include "Common.h"
+#include "IfrParse.h"
+#include "VariableCommon.h"
+#include "BinaryParse.h"
+#include "BinaryCreate.h"
+///
+/// Utility global variables
+///
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 34
+
+#define UTILITY_NAME "FCE"
+
+#define SUCCESS 0
+#define FAIL 1
+#define VR_FAIL 2
+#define MAX_INPUT_ALLOCATE_SIZE 256
+
+///
+/// The type of file input and operations
+///
+typedef enum {
+ INFD,
+ OUTFD,
+ OUTTXT,
+ SETUPTXT
+} FILETYPE;
+
+typedef enum {
+ NONE,
+ READ,
+ UPDATE,
+ UPDATE_REMOVE,
+ UPDATE_IGNORE,
+ VERIFY,
+ UPDATEQ
+} OPERATION_TYPE;
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+ EFI_GUID Guid;
+ CHAR8* Name;
+ CHAR8* Path;
+ struct _GUID_SEC_TOOL_ENTRY *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+///
+/// The tag for use in identifying UNICODE files.
+/// If the file is UNICODE, the first 16 bits of the file will equal this value.
+///
+enum {
+ BigUnicodeFileTag = 0xFEFF,
+ LittleUnicodeFileTag = 0xFFFE
+};
+
+typedef enum {
+ ASCII,
+ BIG_UCS2,
+ LITTLE_UCS2
+} FILE_TYPE;
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+EFI_STATUS
+SynAuthEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the time stamp authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+
+EFI_STATUS
+SynAuthEfiVariableBasedTime (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariableBasedTime (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+**/
+
+EFI_STATUS
+SynEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveNormalEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Read all defaultId and platformId from binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+**/
+VOID
+ReadDefaultAndPlatformIdFromBfv (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+);
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+
+UINT32
+WriteDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+);
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+UINT32
+WriteNvStoreDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+);
+
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToNvStoreBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+
+UINT32
+ReadNvStoreVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Check whether exists the valid normal variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistNormalEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+
+VOID
+FixNvStoreVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+/**
+ Copy time-based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+ @return length The length of storage
+**/
+UINT32
+CopyTimeBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+/**
+ Read time-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadTimeBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Check whether exists the valid time-based variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistTimeBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Fix the size of time-based variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixBasedTimeVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+
+/**
+ Copy Monotonic-Based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyMonotonicBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+/**
+ Read Monotonic-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadMonotonicBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Check whether exists the valid MonotonicBased variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistMonotonicBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Fix the size of montonic variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixMontonicVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+
+/**
+ FCE application entry point
+
+ @param argc The number of input parameters.
+ @param *argv[] The array pointer to the parameters.
+
+ @retval 0 The application exited normally.
+ @retval 1 An error occurred.
+ @retval 2 An error about check occurred.
+
+**/
+int
+main (
+ int argc,
+ char *argv[]
+ );
+
+#endif
diff --git a/BaseTools/Source/C/FCE/GNUmakefile b/BaseTools/Source/C/FCE/GNUmakefile
new file mode 100644
index 0000000000..3e1b6a85e2
--- /dev/null
+++ b/BaseTools/Source/C/FCE/GNUmakefile
@@ -0,0 +1,55 @@
+## @file GNUmakefile
+#
+# GNU makefile for 'FCE' module build.
+#
+# Copyright (c) 2007 - 2018, 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 ARCH
+ #
+ # If ARCH is not defined, then we use 'uname -m' to attempt
+ # try to figure out the appropriate ARCH.
+ #
+ uname_m = $(shell uname -m)
+ $(info Attempting to detect ARCH from 'uname -m': $(uname_m))
+ ifneq (,$(strip $(filter $(uname_m), x86_64 amd64)))
+ ARCH=X64
+ endif
+ ifeq ($(patsubst i%86,IA32,$(uname_m)),IA32)
+ ARCH=IA32
+ endif
+ ifneq (,$(findstring aarch64,$(uname_m)))
+ ARCH=AARCH64
+ endif
+ ifneq (,$(findstring arm,$(uname_m)))
+ ARCH=ARM
+ endif
+ ifndef ARCH
+ $(info Could not detected ARCH from uname results)
+ $(error ARCH is not defined!)
+ endif
+ $(info Detected ARCH of $(ARCH) using uname.)
+endif
+
+export ARCH
+export HOST_ARCH=$(ARCH)
+
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = FCE
+
+OBJECTS = Fce.o Variable.o TimeBasedVariable.o MonotonicBasedVariable.o IfrParse.o Common.o BinaryParse.o BinaryCreate.o Expression.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
+LIBS = -lCommon -lm
+
+
diff --git a/BaseTools/Source/C/FCE/IfrParse.h b/BaseTools/Source/C/FCE/IfrParse.h
new file mode 100644
index 0000000000..29a878a191
--- /dev/null
+++ b/BaseTools/Source/C/FCE/IfrParse.h
@@ -0,0 +1,789 @@
+/** @file
+
+ Parser for IFR binary encoding.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IFR_PARSE_H_
+#define _IFR_PARSE_H_
+
+#include "Common.h"
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/MdeModuleHii.h>
+
+//
+// Scope for Browser action. It may be Form, FormSet or System level.
+//
+typedef enum {
+ FormLevel,
+ FormSetLevel,
+ SystemLevel,
+ MaxLevel
+} BROWSER_SETTING_SCOPE;
+
+///
+///Old EFI_IFR_VARSTORE_EFI structure to complible with UEFI 2.3
+///
+typedef struct _EFI_IFR_VARSTORE_EFI_OLD {
+ EFI_IFR_OP_HEADER Header;
+ EFI_VARSTORE_ID VarStoreId;
+ EFI_GUID Guid;
+ UINT32 Attributes;
+} EFI_IFR_VARSTORE_EFI_OLD;
+
+///
+/// The languages used in HII DB
+///
+typedef enum {
+ UQI,
+ EN_US,
+ ENG
+} LANGUAGE;
+
+///
+/// Define the structure for the parameters of Uqi and Uqi List
+///
+typedef struct _FORM_BROWSER_STATEMENT FORM_BROWSER_STATEMENT;
+
+typedef enum {
+ ONE_OF,
+ NUMERIC,
+ CHECKBOX,
+ STRING,
+ ORDERED_LIST
+} QUEST_TYPE;
+
+typedef struct {
+ UINT16 *DefaultId;
+ UINT64 *PlatformId;
+ UINT32 IdNum;
+ UINT32 HexNum;
+ QUEST_TYPE Type;
+ CHAR16 *Data;
+ UINT8 *Value;
+ UINT8 *DiffValue;
+ UINT32 ScriptsLine;
+ FORM_BROWSER_STATEMENT *Question;
+} UQI_HEADER;
+
+typedef struct _UQI_PARAM_LIST {
+ struct _UQI_PARAM_LIST *Next;
+ UQI_HEADER Header;
+ BOOLEAN ParseOrNot;
+ BOOLEAN SameOrNot;
+ BOOLEAN ErrorOrNot;
+ CHAR8 *Error;
+} UQI_PARAM_LIST;
+
+//
+// Incremental size of stack for expression
+//
+#define EXPRESSION_STACK_SIZE_INCREMENT 0x100
+
+//
+// IFR relative definition
+//
+#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0
+#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1
+#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2
+#define EFI_HII_EXPRESSION_SUPPRESS_IF 3
+#define EFI_HII_EXPRESSION_DISABLE_IF 4
+#define EFI_HII_EXPRESSION_VALUE 5
+#define EFI_HII_EXPRESSION_RULE 6
+#define EFI_HII_EXPRESSION_READ 7
+#define EFI_HII_EXPRESSION_WRITE 8
+#define EFI_HII_EXPRESSION_WARNING_IF 9
+
+#define EFI_HII_VARSTORE_BUFFER 0
+#define EFI_HII_VARSTORE_NAME_VALUE 1
+#define EFI_HII_VARSTORE_EFI_VARIABLE 2
+#define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3
+
+#define FORM_INCONSISTENT_VALIDATION 0
+#define FORM_NO_SUBMIT_VALIDATION 1
+
+typedef struct {
+ //
+ // HII Data Type
+ //
+ UINT8 Type;
+ //
+ // Buffer Data and Length if Type is EFI_IFR_TYPE_BUFFER or EFI_IFR_TYPE_STRING
+ //
+ UINT8 *Buffer;
+ UINT16 BufferLen;
+ EFI_IFR_TYPE_VALUE Value;
+} EFI_HII_VALUE;
+
+#define NAME_VALUE_NODE_SIGNATURE SIGNATURE_32 ('N', 'V', 'S', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ CHAR16 *Name;
+ CHAR16 *Value;
+ CHAR16 *EditValue;
+} NAME_VALUE_NODE;
+
+#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE)
+
+#define FORMSET_STORAGE_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'G')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT64 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT32 DefaultPlatformIdNum;
+ UINT32 FormSetOrder;
+
+ BOOLEAN NewEfiVarstore; //EfiVarStore for UEFI 2.31 or not
+ BOOLEAN Skip; //Flag for sorting out the variables
+
+ UINT8 Type; // Storage type
+
+ UINT16 VarStoreId;
+ EFI_GUID Guid;
+
+ CHAR16 *Name; // For EFI_IFR_VARSTORE
+ UINT16 Size;
+ UINT8 *Buffer;
+
+ LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE
+
+ UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
+} FORMSET_STORAGE;
+
+#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE)
+
+typedef union {
+ EFI_STRING_ID VarName;
+ UINT16 VarOffset;
+} VAR_STORE_INFO;
+
+#define EXPRESSION_OPCODE_SIGNATURE SIGNATURE_32 ('E', 'X', 'O', 'P')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Operand;
+
+ UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND
+ UINT8 Flags; // For EFI_IFR_SPAN
+ UINT8 RuleId; // For EFI_IFR_RULE_REF
+
+ EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1
+
+ EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_VAL_LIST, EFI_IFR_QUESTION_REF1
+ EFI_QUESTION_ID QuestionId2;
+
+ UINT16 ListLength; // For EFI_IFR_EQ_ID_VAL_LIST
+ UINT16 *ValueList;
+
+ EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3
+ EFI_GUID Guid;
+
+ FORMSET_STORAGE *VarStorage; // For EFI_IFR_SET, EFI_IFR_GET
+ VAR_STORE_INFO VarStoreInfo;// For EFI_IFR_SET, EFI_IFR_GET
+ UINT8 ValueType; // For EFI_IFR_SET, EFI_IFR_GET
+ UINT8 ValueWidth; // For EFI_IFR_SET, EFI_IFR_GET
+ CHAR16 *ValueName; // For EFI_IFR_SET, EFI_IFR_GET
+ LIST_ENTRY MapExpressionList; // nested expressions inside of Map opcode.
+} EXPRESSION_OPCODE;
+
+#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE)
+
+#define FORM_EXPRESSION_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'P')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Type; // Type for this expression
+
+ UINT8 RuleId; // For EFI_IFR_RULE only
+ EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only
+
+ EFI_HII_VALUE Result; // Expression evaluation result
+ UINT8 TimeOut; // For EFI_IFR_WARNING_IF
+
+ LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE)
+} FORM_EXPRESSION;
+
+#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE)
+
+#define QUESTION_DEFAULT_SIGNATURE SIGNATURE_32 ('Q', 'D', 'F', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId;
+ EFI_HII_VALUE Value; // Default value
+
+ FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE
+} QUESTION_DEFAULT;
+
+#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE)
+
+#define QUESTION_OPTION_SIGNATURE SIGNATURE_32 ('Q', 'O', 'P', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_STRING_ID Text;
+ UINT8 Flags;
+ EFI_HII_VALUE Value;
+
+ FORM_EXPRESSION *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf
+} QUESTION_OPTION;
+
+#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE)
+
+#define FORM_BROWSER_STATEMENT_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'A')
+
+struct _FORM_BROWSER_STATEMENT {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINT8 Operand; // The operand (first byte) of this Statement or Question
+
+ UQI_HEADER Uqi;
+ UINT32 FormSetOrder;
+ EFI_GUID Guid;
+ UINT8 Type; // Storage type
+ BOOLEAN NewEfiVarstore; //EfiVarStore for UEFI 2.31 or not
+ UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
+ BOOLEAN QuestionReferToBitField;// Whether the question is stored in a bit field.
+ //
+ // Statement Header
+ //
+ EFI_STRING_ID Prompt;
+ EFI_STRING_ID Help;
+ EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT
+
+ //
+ // Question Header
+ //
+ EFI_QUESTION_ID QuestionId; // The value of zero is reserved
+ EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage
+ FORMSET_STORAGE *Storage;
+ VAR_STORE_INFO VarStoreInfo;
+ UINT16 StorageWidth;
+ UINT16 BitStorageWidth;
+ UINT16 BitVarOffset;
+ UINT8 QuestionFlags;
+ CHAR16 *VariableName; // Name/Value or EFI Variable name
+
+ EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof
+ UINT8 *BufferValue; // Edit copy for string, password, orderedlist
+ UINT8 ValueType; // Data type for orderedlist value array
+
+ //
+ // OpCode specific members
+ //
+ UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF,
+ // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER
+ UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST
+
+ UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number
+
+ UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value
+ UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length
+ UINT64 Step;
+
+ EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON
+ EFI_GUID RefreshGuid; // for EFI_IFR_REFRESH_ID
+
+ //
+ // Get from IFR parsing
+ //
+ FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly
+ LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values
+ LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION)
+
+ EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE
+ UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh
+ BOOLEAN InSubtitle; // nesting inside of EFI_IFR_SUBTITLE
+
+ LIST_ENTRY InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION)
+ LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION)
+ LIST_ENTRY WarningListHead; // nested warning expression list (FORM_EXPRESSION)
+ FORM_EXPRESSION *GrayOutExpression; // nesting inside of GrayOutIf
+ FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf
+ FORM_EXPRESSION *DisableExpression; // nesting inside of DisableIf
+
+ FORM_EXPRESSION *ReadExpression; // nested EFI_IFR_READ, provide this question value by read expression.
+ FORM_EXPRESSION *WriteExpression; // nested EFI_IFR_WRITE, evaluate write expression after this question value is set.
+};
+
+#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE)
+
+#define FORM_BROWSER_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M')
+#define STANDARD_MAP_FORM_TYPE 0x01
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 FormId; // FormId of normal form or formmap form.
+ EFI_STRING_ID FormTitle; // FormTile of normal form, or FormMapMethod title of formmap form.
+ UINT16 FormType; // Specific form type for the different form.
+
+ BOOLEAN ModalForm; // Whether this is a modal form.
+ LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
+ LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT)
+ FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf
+} FORM_BROWSER_FORM;
+
+#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE)
+
+#define FORMSET_DEFAULTSTORE_SIGNATURE SIGNATURE_32 ('F', 'D', 'F', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId;
+ EFI_STRING_ID DefaultName;
+} FORMSET_DEFAULTSTORE;
+
+#define STRING_NUMBER 100
+
+typedef struct {
+ EFI_STRING_ID StringId;
+ CHAR16 *String;
+} STRING_INFO;
+
+typedef struct {
+ EFI_STRING_ID CachedIdNum;
+ EFI_STRING_ID MaxIdNum;
+ STRING_INFO *StringInfoList;
+} FORMSET_STRING_LIST;
+
+#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE)
+
+#define FORM_BROWSER_FORMSET_SIGNATURE SIGNATURE_32 ('F', 'B', 'F', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT32 FormSetOrder;
+
+ UINTN IfrBinaryLength;
+ UINT8 *IfrBinaryData;
+ UINT8 *UnicodeBinary;
+
+ EFI_GUID Guid;
+ EFI_STRING_ID FormSetTitle;
+ EFI_STRING_ID Help;
+ UINT8 NumberOfClassGuid;
+ EFI_GUID ClassGuid[3]; // Up to three ClassGuid
+ UINT16 Class; // Tiano extended Class code
+ UINT16 SubClass; // Tiano extended Subclass code
+
+ FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions
+ EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode
+
+ LIST_ENTRY *StorageListHead; // Storage list (FORMSET_STORAGE)
+ LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE)
+ LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM)
+ LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
+ FORMSET_STRING_LIST EnUsStringList; // Cache EN_US English list
+ FORMSET_STRING_LIST UqiStringList; // Cache EN_US English list
+} FORM_BROWSER_FORMSET;
+
+#define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE)
+
+///
+/// Structure for multi-platform support
+///
+typedef struct {
+ UINT16 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 DefaultIdNum;
+ UINT64 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 PlatformIdNum;
+ UINT16 KeyDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT64 KeyPlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 KeyIdNum;
+ FORM_BROWSER_STATEMENT PlatformIdQuestion;
+ FORM_BROWSER_STATEMENT *Question;
+ UINT16 PlatformIdWidth;
+ UQI_HEADER Uqi;
+ BOOLEAN MultiPlatformOrNot;
+ BOOLEAN ExistStorageFfsInBfv;
+ BOOLEAN SizeOptimized;
+ BOOLEAN SizeOptimizedParam;
+} MULTI_PLATFORM_PARAMETERS;
+
+/**
+ Search the variable list according to the variable Guid and name, and return the pointer
+ of that Node.
+
+ @param HiiObjList The pointer to the Question
+ @param VarName The EFI variable name need to be updated to VarList
+ @param Offset The offset of the variable
+ @param StorageListHead The pointer to the LIST_ENTRY of Storage
+ @param Vaue The value in that value offset of the variable
+ @param VarList The dual pointer of Varlist
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+SearchVarStorage (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16* VarName,
+ IN UINT32 Offset,
+ IN LIST_ENTRY *StorageListHead,
+ IN OUT CHAR8 **Value,
+ IN OUT FORMSET_STORAGE **VarList
+ );
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN UINT8 *UniPackge
+ );
+
+/**
+ Free resources allocated for all Storage in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllStorage (
+ IN LIST_ENTRY *StorageEntryListHead
+ );
+
+
+/**
+ Free resources allocated for a FormSet.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+
+/**
+ Free resources allocated for all FormSet in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllFormSet (
+ IN LIST_ENTRY *FormSetEntryListHead
+ );
+
+/**
+ Parse opcodes in the formset IFR binary.
+
+ @param FormSet Pointer of the FormSet data structure.
+
+ @retval EFI_SUCCESS Opcode parse success.
+ @retval Other Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Set the value to the variable of platformId question.
+
+ @param PlatformId The form set.
+
+ @retval EFI_SUCCESS Set successfully.
+
+**/
+EFI_STATUS
+AssignThePlatformId (
+ IN UINT64 PlatformId
+ );
+
+
+/**
+ Reset Questions to their default value in a Form, Formset or System.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param DefaultId The default Id
+ @param PlatformId The platform Id
+ @param SettingScope Setting Scope for Default action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ );
+
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+ VOID
+ );
+
+
+/**
+ Push current expression onto the Stack
+
+ @param Pointer Pointer to current expression.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+ IN VOID *Pointer
+ );
+
+
+/**
+ Pop current expression from the Stack
+
+ @param Pointer Pointer to current expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+ OUT VOID **Pointer
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+ VOID
+ );
+
+
+/**
+ Push the list of map expression onto the Stack
+
+ @param Pointer Pointer to the list of map expression to be pushed.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+ IN VOID *Pointer
+ );
+
+
+/**
+ Pop the list of map expression from the Stack
+
+ @param Pointer Pointer to the list of map expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+ OUT VOID **Pointer
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+ VOID
+ );
+
+
+/**
+ Push an Operand onto the Stack
+
+ @param Operand Operand to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushScope (
+ IN UINT8 Operand
+ );
+
+
+/**
+ Pop an Operand from the Stack
+
+ @param Operand Operand to pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PopScope (
+ OUT UINT8 *Operand
+ );
+
+
+/**
+ Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+ @param Value HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+ IN EFI_HII_VALUE *Value
+ );
+
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+
+ @retval EFI_INVALID_PARAMETER Could not perform compare on two values.
+ @retval 0 Two operators equal.
+ @return Positive value if Value1 is greater than Value2.
+ @retval Negative value if Value1 is less than Value2.
+
+**/
+INTN
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Evaluate the result of a HII expression.
+
+ If Expression is NULL, then ASSERT.
+
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+ @param Expression Expression to be evaluated.
+ @param ConstantExpression The pointer to the flag of constant expression. If constant, will return TRUE.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
+ could not be found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_EXPRESSION *Expression,
+ IN OUT BOOLEAN *ConstantExpression
+ );
+
+/**
+ Compare two Uqi parameters
+
+ @param UqiParm1 The pointer to the first Uqi parameter.
+ @param UqiParm2 The pointer to the second Uqi parameter.
+
+ @retval TRUE If these two Uqi parameters are the same, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+BOOLEAN
+CompareUqiHeader (
+ IN CONST UQI_HEADER *UqiParm1,
+ IN CONST UQI_HEADER *UqiParm2
+ );
+
+
+/**
+ Print all ONE_OF ORDER_LIST NUMERIC STRING and CHECKBOX in all fromsets.
+
+ @param Formset The pointer to the entry of the fromset list
+ @param Formset The pointer to the entry of the storage list
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+PrintInfoInAllFormset (
+ IN LIST_ENTRY *FormSetEntryListHead,
+ IN LIST_ENTRY *StorageEntryListHead
+ );
+
+ /**
+ Get the question value with bit field from the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value get from.
+ @param Value Retun the value.
+
+**/
+VOID
+GetBitsQuestionValue(
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT8 *Buffer,
+ OUT UINT32 *Value
+ );
+
+/**
+ Set the question value with bit field to the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value set to.
+ @param Value The value need to set.
+
+**/
+VOID
+SetBitsQuestionValue (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT8 *Buffer,
+ IN UINT32 Value
+ );
+
+#endif
diff --git a/BaseTools/Source/C/FCE/Makefile b/BaseTools/Source/C/FCE/Makefile
new file mode 100644
index 0000000000..cc33a42a42
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Makefile
@@ -0,0 +1,19 @@
+## @file
+#
+# Windows makefile for 'FCE' module build.
+#
+#Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+#SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = FCE
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = Fce.obj Variable.obj TimeBasedVariable.obj MonotonicBasedVariable.obj IfrParse.obj Common.obj BinaryParse.obj BinaryCreate.obj Expression.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
diff --git a/BaseTools/Source/C/FCE/MonotonicBasedVariable.h b/BaseTools/Source/C/FCE/MonotonicBasedVariable.h
new file mode 100644
index 0000000000..11fc51ed38
--- /dev/null
+++ b/BaseTools/Source/C/FCE/MonotonicBasedVariable.h
@@ -0,0 +1,162 @@
+/** @file
+
+ The header of MonotonicBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_H__
+
+#define EFI_AUTHENTICATED_VARIABLE_GUID \
+ { 0x515fa686, 0xb06e, 0x4550, { 0x91, 0x12, 0x38, 0x2b, 0xf1, 0x6, 0x7b, 0xfb }}
+
+extern EFI_GUID gEfiAuthenticatedVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1
+/// * For IA-64 architecture: 8
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT 8
+#else
+#define ALIGNMENT 1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition
+#define VAR_DELETED 0xfd ///< Variable is obsolete
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid
+#define VAR_ADDED 0x3f ///< Variable has been completely added
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI spec
+ ///
+ UINT32 Attributes;
+ ///
+ /// Associated monotonic count value against replay attack.
+ ///
+ UINT64 MonotonicCount;
+ ///
+ /// Index of associated public key in database.
+ ///
+ UINT32 PubKeyIndex;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI spec.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/BaseTools/Source/C/FCE/TimeBasedVariable.h b/BaseTools/Source/C/FCE/TimeBasedVariable.h
new file mode 100644
index 0000000000..3ffd939443
--- /dev/null
+++ b/BaseTools/Source/C/FCE/TimeBasedVariable.h
@@ -0,0 +1,166 @@
+/** @file
+
+ The header of TimeBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_BASED_TIME_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_BASED_TIME_H__
+
+#define EFI_AUTHENTICATED_VARIABLE_BASED_TIME_GUID \
+ { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
+
+extern EFI_GUID gEfiAuthenticatedVariableBasedTimeGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1
+/// * For IA-64 architecture: 8
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT 8
+#else
+#define ALIGNMENT 1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition
+#define VAR_DELETED 0xfd ///< Variable is obsolete
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid
+#define VAR_ADDED 0x3f ///< Variable has been completely added
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI spec
+ ///
+ UINT32 Attributes;
+ ///
+ /// Associated monotonic count value against replay attack.
+ ///
+ UINT64 MonotonicCount;
+ ///
+ /// Associated TimeStamp value against replay attack.
+ ///
+ EFI_TIME TimeStamp;
+ ///
+ /// Index of associated public key in database.
+ ///
+ UINT32 PubKeyIndex;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI spec.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/BaseTools/Source/C/FCE/Variable.h b/BaseTools/Source/C/FCE/Variable.h
new file mode 100644
index 0000000000..35b88e045c
--- /dev/null
+++ b/BaseTools/Source/C/FCE/Variable.h
@@ -0,0 +1,154 @@
+/** @file
+
+ The header of Variable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_FORMAT_H__
+#define __VARIABLE_FORMAT_H__
+
+#define EFI_VARIABLE_GUID \
+ { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } }
+
+extern EFI_GUID gEfiVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1.
+/// * For IA-64 architecture: 8.
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT 8
+#else
+#define ALIGNMENT 1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region.
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region.
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State.
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header.
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags.
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition.
+#define VAR_DELETED 0xfd ///< Variable is obsolete.
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid.
+#define VAR_ADDED 0x3f ///< Variable has been completely added.
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI specification.
+ ///
+ UINT32 Attributes;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI specification.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/BaseTools/Source/C/FCE/VariableCommon.h b/BaseTools/Source/C/FCE/VariableCommon.h
new file mode 100644
index 0000000000..7389902076
--- /dev/null
+++ b/BaseTools/Source/C/FCE/VariableCommon.h
@@ -0,0 +1,55 @@
+/** @file
+
+ The header of common Variable.c TimeBasedVariable.c and MonotonicBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_COMMON_H__
+#define __VARIABLE_COMMON_H__
+
+/**
+ Check the store variable is no-authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If no-authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckNormalVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ );
+/**
+ Check the store variable is Monotonic based authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckMonotonicBasedVarStore (
+ IN VOID *VariableStoreHeader
+ );
+
+/**
+ Check the store variable is Time stamp authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+BOOLEAN
+CheckTimeBasedVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ );
+
+
+
+#endif // _EFI_VARIABLE_COMMON_H_
diff --git a/BaseTools/Source/C/GNUmakefile b/BaseTools/Source/C/GNUmakefile
index 824f0306e6..990c6d0a82 100644
--- a/BaseTools/Source/C/GNUmakefile
+++ b/BaseTools/Source/C/GNUmakefile
@@ -1,7 +1,7 @@
## @file
# GNU/Linux makefile for C tools build.
#
-# Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -49,6 +49,7 @@ APPLICATIONS = \
VfrCompile \
BfmLib \
EfiRom \
+ FCE \
GenFfs \
GenFv \
GenFw \
diff --git a/BaseTools/Source/C/Makefile b/BaseTools/Source/C/Makefile
index a6d39eb864..357e8b9003 100644
--- a/BaseTools/Source/C/Makefile
+++ b/BaseTools/Source/C/Makefile
@@ -1,7 +1,7 @@
## @file
# Windows makefile for C tools build.
#
-# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
HOST_ARCH = IA32
@@ -14,6 +14,7 @@ APPLICATIONS = \
BrotliCompress \
BfmLib \
EfiRom \
+ FCE \
GenCrc32 \
GenFfs \
GenFv \
--
2.13.0.windows.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Patch v3 3/3] BaseTools: Add a tool FMMT
2019-07-01 11:27 [Patch v3 0/3] BaseTools: Move FCE & FMMT tools to edk2 repo Liming Gao
2019-07-01 11:27 ` [Patch v3 1/3] BaseTools: Add a tool BfmLib Liming Gao
2019-07-01 11:27 ` [Patch v3 2/3] BaseTools: Add a tool FCE Liming Gao
@ 2019-07-01 11:27 ` Liming Gao
2 siblings, 0 replies; 4+ messages in thread
From: Liming Gao @ 2019-07-01 11:27 UTC (permalink / raw)
To: devel; +Cc: Shenglei Zhang, Bob Feng
From: Shenglei Zhang <shenglei.zhang@intel.com>
FMMT is a tool to enable removal, addition and replacement of
FFS files in FD image binaries.
https://bugzilla.tianocore.org/show_bug.cgi?id=1847
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
Reviewed-by: Bob Feng <bob.c.feng@intel.com>
---
BaseTools/Source/C/FMMT/FirmwareModuleManagement.c | 2559 ++++++++++
BaseTools/Source/C/FMMT/FmmtLib.c | 5051 ++++++++++++++++++++
BaseTools/Source/C/FMMT/Rebase.c | 846 ++++
BaseTools/BinWrappers/PosixLike/FMMT | 29 +
BaseTools/Source/C/FMMT/FirmwareModuleManagement.h | 479 ++
BaseTools/Source/C/FMMT/FmmtConf.ini | 6 +
BaseTools/Source/C/FMMT/GNUmakefile | 16 +
BaseTools/Source/C/FMMT/Makefile | 17 +
BaseTools/Source/C/FMMT/Rebase.h | 31 +
BaseTools/Source/C/GNUmakefile | 1 +
BaseTools/Source/C/Makefile | 1 +
11 files changed, 9036 insertions(+)
create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.c
create mode 100644 BaseTools/Source/C/FMMT/FmmtLib.c
create mode 100644 BaseTools/Source/C/FMMT/Rebase.c
create mode 100755 BaseTools/BinWrappers/PosixLike/FMMT
create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.h
create mode 100644 BaseTools/Source/C/FMMT/FmmtConf.ini
create mode 100644 BaseTools/Source/C/FMMT/GNUmakefile
create mode 100644 BaseTools/Source/C/FMMT/Makefile
create mode 100644 BaseTools/Source/C/FMMT/Rebase.h
diff --git a/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c
new file mode 100644
index 0000000000..63ae3c45a4
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c
@@ -0,0 +1,2559 @@
+/** @file
+
+ FMMT main routine.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FirmwareModuleManagement.h"
+#include "Rebase.h"
+#include <stdlib.h>
+#include <wchar.h>
+
+CHAR8* mGuidToolDefinition = "FmmtConf.ini";
+extern EFI_FIRMWARE_VOLUME_HEADER *mFvHeader;
+extern UINT32 mFvLength;
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+#define EFI_FFS_VOLUME_TOP_FILE_GUID \
+{ \
+ 0x1BA0062E, 0xC779, 0x4582, { 0x85, 0x66, 0x33, 0x6A, 0xE8, 0xF7, 0x8F, 0x09 } \
+}
+#define FSP_FFS_INFORMATION_FILE_GUID \
+{ 0x912740be, 0x2284, 0x4734, { 0xb9, 0x71, 0x84, 0xb0, 0x27, 0x35, 0x3f, 0x0c }};
+
+static EFI_GUID mVTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
+static EFI_GUID mFSPGuid = FSP_FFS_INFORMATION_FILE_GUID;
+
+
+/**
+
+Routine Description:
+
+ The Usage of FMMT tool.
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+**/
+VOID
+Usage (
+ VOID
+ )
+{
+ //
+ // Summary usage
+ //
+ fprintf (stdout, "Usage: %s [options] \n\n", UTILITY_SHORT_NAME);
+
+ //
+ // Copyright declaration
+ //
+ fprintf (stdout, "Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.\n\n");
+
+ //
+ // Details Option
+ //
+ fprintf (stdout, "Options:\n");
+
+ //
+ // Command Line for View
+ //
+ fprintf (stdout, " -v <input-binary-file>\n\
+ View each FV and the named files within each FV.\n");
+
+ //
+ // Command Line for Delete entire FV
+ //
+ fprintf (stdout, " -d <input-binary-file> <FV-id> <output-binary-file>\n\
+ Delete the entire FV in an FD binary\n");
+
+ //
+ // Command Line for Delete file from FV
+ //
+ fprintf (stdout, " -d <input-binary-file> <FV-id> <File-Name> [<FV-id> <File-Name> ...] <output-binary-file>\n\
+ Delete a file (or files) from the firmware volume in an FD binary\n");
+
+ //
+ // Command Line for Add
+ //
+ fprintf (stdout, " -a <input-binary-file> <FV-id> <NewFilePath> [<FV-id> <NewFilePath> ...] <output-binary-file>\n\
+ Add a file (or files) to the firmware volume in an FD binary\n");
+
+ //
+ // Command Line for Replace
+ //
+ fprintf (stdout, " -r <input-binary-file> <FV-id> <File-Name> <NewFilePath> [<FV-id> <File-Name> <NewFilePath> ...] <output-binary-file>\n\
+ The replace command combines the functionality of remove and add into a single operation.\n");
+
+ fprintf (stdout, "\nNote:\n");
+ fprintf (stdout, " <FV-id> is the sequence of the firmware volume included in the FD image, it both support the sequentially format like FV0, FV1 and the FV's file guid value format.\n");
+ return;
+}
+
+
+BOOLEAN
+IsVtf(EFI_FFS_FILE_HEADER2* ffs) {
+ if (!memcmp(&ffs->Name, &mVTFGuid, sizeof (EFI_GUID))) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+BOOLEAN
+IsFsp(EFI_FFS_FILE_HEADER2* ffs) {
+ if (!memcmp(&ffs->Name, &mFSPGuid, sizeof (EFI_GUID))) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static
+EFI_STATUS
+GetBaseAddrFromVtf(FIRMWARE_DEVICE *FdData, CHAR8 *FvId, UINT64 *BaseAddr) {
+ EFI_STATUS Status;
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *FvInFd;
+
+ Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Get bottom FV
+ //
+ CurrentFv = FdData->Fv;
+ while (CurrentFv->FvNext) {
+ CurrentFv = CurrentFv->FvNext;
+ }
+ if (CurrentFv->FfsNumbers > 0 && IsVtf(&CurrentFv->FfsHeader[CurrentFv->FfsNumbers])) {
+ //
+ // Found VTF at the top of FV
+ // Assume 4G address
+ //
+ *BaseAddr = 0x100000000 - (FdData->Size - FvInFd->ImageAddress);
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+static
+EFI_STATUS
+GetBaseAddrFromFsp(FIRMWARE_DEVICE *FdData, CONST UINT8* FdBuffer, CHAR8 *FvId, UINT64 *BaseAddr)
+{
+ EFI_STATUS Status;
+ FV_INFORMATION *FvInFd;
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *FspFv;
+ UINT32 Offset;
+ UINT64 ImageSize;
+ UINT64 Size;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ BOOLEAN FspFound;
+
+ Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ ImageSize = 0;
+ Size = 0;
+ FspFound = FALSE;
+ FspFv = NULL;
+ CurrentFv = FdData->Fv;
+ while (CurrentFv) {
+ if (CurrentFv->FfsNumbers > 0 && IsFsp(&CurrentFv->FfsHeader[0])) {
+ Offset = CurrentFv->ImageAddress + CurrentFv->FfsAttuibutes[0].Offset;
+ CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
+ //
+ // Skip FFS header
+ //
+ Offset += GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)CurrentFile);
+ //
+ // Stip section header
+ //
+ Offset += GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)(FdBuffer + Offset));
+ //
+ // We have raw FSP here, and 24 is the image size
+ //
+ ImageSize = *((UINT32 *)(FdBuffer + Offset + 24));
+ //
+ // 28 is the base address
+ //
+ *BaseAddr = *((UINT32 *)(FdBuffer + Offset + 28));
+ FspFound = TRUE;
+ FspFv = CurrentFv;
+ }
+ if (CurrentFv == FvInFd){
+ break;
+ }
+ CurrentFv = CurrentFv->FvNext;
+ }
+ if (!FspFound) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Check if FSP binary contains this FV
+ //
+ while (FspFv != NULL) {
+ Size += FspFv->FvHeader->FvLength;
+ if (FspFv == FvInFd) {
+ break;
+ }
+ FspFv = FspFv->FvNext;
+ }
+ if (Size <= ImageSize) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+static
+VOID
+AddPadFile(EFI_FIRMWARE_VOLUME_HEADER *Fv, EFI_FFS_FILE_HEADER2 *PadFile, UINT32 PadFileSize) {
+ UINT32 hdrSize;
+
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset(PadFile, -1, PadFileSize);
+ }
+ else {
+ memset(PadFile, 0, PadFileSize);
+ }
+ PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
+ PadFile->Attributes = 0;
+
+ //
+ // Write pad file size (calculated size minus next file header size)
+ //
+ if (PadFileSize >= MAX_FFS_SIZE) {
+ memset(PadFile->Size, 0, sizeof(UINT8)* 3);
+ ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize;
+ PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
+ hdrSize = sizeof(EFI_FFS_FILE_HEADER2);
+ }
+ else {
+ PadFile->Size[0] = (UINT8)(PadFileSize & 0xFF);
+ PadFile->Size[1] = (UINT8)((PadFileSize >> 8) & 0xFF);
+ PadFile->Size[2] = (UINT8)((PadFileSize >> 16) & 0xFF);
+ hdrSize = sizeof(EFI_FFS_FILE_HEADER);
+ }
+
+ //
+ // Fill in checksums and state, they must be 0 for checksumming.
+ //
+ PadFile->IntegrityCheck.Checksum.Header = 0;
+ PadFile->IntegrityCheck.Checksum.File = 0;
+ PadFile->State = 0;
+ PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8((UINT8 *)PadFile, hdrSize);
+ PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
+
+ PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ PadFile->State = (UINT8)~(PadFile->State);
+ }
+}
+
+static
+UINT8* ReadFileToBuffer(CONST CHAR8 *FdName, UINT32 *FdSize) {
+ FILE* file;
+
+ UINT8 *FdBuffer = NULL;
+
+ file = fopen(FdName, "rb");
+ if (file == NULL)
+ return NULL;
+
+ fseek(file, 0, SEEK_SET);
+ fseek(file, 0, SEEK_END);
+ *FdSize = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ FdBuffer = malloc(*FdSize);
+ if (FdBuffer == NULL) {
+ goto FAIL;
+ }
+ if (fread(FdBuffer, 1, *FdSize, file) != *FdSize) {
+ goto FAIL;
+ }
+ fclose(file);
+ return FdBuffer;
+FAIL:
+ free(FdBuffer);
+ fclose(file);
+ return NULL;
+}
+
+static UINT32 CalcuFfsSize(EFI_FIRMWARE_VOLUME_HEADER* Fv, CONST EFI_FFS_FILE_HEADER2 *Ffs) {
+ EFI_FFS_FILE_HEADER2 *NextFile;
+ UINTN FfsSize;
+ UINTN FvSize;
+ UINTN Offset;
+
+ FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)Ffs);
+ FfsSize += (UINT8 *)ALIGN_POINTER(((UINT8 *)Ffs + FfsSize), 8) - ((UINT8 *)Ffs + FfsSize);
+ FvBufGetSize(Fv, &FvSize);
+ Offset = (UINT8 *)Ffs - (UINT8 *)Fv;
+ if (Offset + FfsSize < FvSize) {
+ NextFile = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)Ffs + FfsSize);
+ if (NextFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ FfsSize += GetFfsFileLength((EFI_FFS_FILE_HEADER *)NextFile);
+ }
+ }
+ return FfsSize;
+}
+
+static
+EFI_STATUS
+ReadFfsAlignment(
+IN EFI_FFS_FILE_HEADER *FfsFile,
+IN OUT UINT32 *Alignment
+)
+{
+ //
+ // Verify input parameters.
+ //
+ if (FfsFile == NULL || Alignment == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch ((FfsFile->Attributes >> 3) & 0x07) {
+
+ case 0:
+ //
+ // 1 byte alignment
+ //
+ *Alignment = 0;
+ break;
+
+ case 1:
+ //
+ // 16 byte alignment
+ //
+ *Alignment = 4;
+ break;
+
+ case 2:
+ //
+ // 128 byte alignment
+ //
+ *Alignment = 7;
+ break;
+
+ case 3:
+ //
+ // 512 byte alignment
+ //
+ *Alignment = 9;
+ break;
+
+ case 4:
+ //
+ // 1K byte alignment
+ //
+ *Alignment = 10;
+ break;
+
+ case 5:
+ //
+ // 4K byte alignment
+ //
+ *Alignment = 12;
+ break;
+
+ case 6:
+ //
+ // 32K byte alignment
+ //
+ *Alignment = 15;
+ break;
+
+ case 7:
+ //
+ // 64K byte alignment
+ //
+ *Alignment = 16;
+ break;
+
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+static
+BOOLEAN
+ReplaceFfs(EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, EFI_FFS_FILE_HEADER2 *OldFfs) {
+ UINT32 FfsSize;
+ UINT32 NewFileSize;
+ UINT32 Offset;
+ UINT32 Align;
+ UINT32 HdrSize;
+ UINT32 PadSize;
+ EFI_FFS_FILE_HEADER2 *Pad;
+
+ Align = 0;
+ PadSize = 0;
+ Pad = NULL;
+ ReadFfsAlignment((EFI_FFS_FILE_HEADER *)InputFfs, &Align);
+ Align = 1 << Align;
+ HdrSize = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+ FfsSize = CalcuFfsSize(Fv, OldFfs);
+ //
+ // Align data
+ //
+ if ((((UINT8 *)OldFfs - (UINT8 *)Fv) + HdrSize) % Align != 0) {
+ PadSize = ((UINT8 *)OldFfs - (UINT8 *)Fv) + sizeof (EFI_FFS_FILE_HEADER)+HdrSize;
+ while (PadSize % Align != 0) {
+ PadSize++;
+ }
+ PadSize -= HdrSize;
+ PadSize -= ((UINT8 *)OldFfs - (UINT8 *)Fv);
+ if (FfsSize < PadSize) {
+ return FALSE;
+ }
+ FfsSize -= PadSize;
+ Pad = OldFfs;
+ OldFfs = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + PadSize);
+ }
+
+ NewFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+ Offset = (UINT8 *)ALIGN_POINTER(((UINT8 *)OldFfs + NewFileSize), 8) - ((UINT8 *)OldFfs + NewFileSize);
+ if (FfsSize >= NewFileSize && FfsSize - NewFileSize <= 7) {
+ memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset((UINT8 *)OldFfs + NewFileSize, -1, FfsSize - NewFileSize);
+ }
+ else {
+ memset((UINT8 *)OldFfs + NewFileSize, 0, FfsSize - NewFileSize);
+ }
+ }
+ else if (FfsSize >= NewFileSize + sizeof(EFI_FFS_FILE_HEADER) + Offset) {
+ memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
+ AddPadFile(
+ Fv,
+ (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + NewFileSize + Offset),
+ FfsSize - NewFileSize - Offset
+ );
+ }
+ else {
+ return FALSE;
+ }
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ OldFfs->State = (UINT8)~(InputFfs->State);
+ }
+ if (PadSize != 0) {
+ AddPadFile(Fv, Pad, PadSize);
+ }
+ return TRUE;
+}
+
+static
+
+EFI_STATUS
+AddFfs(UINT8 *FdBuffer, UINT32 ImageAddress, EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, UINT32 *OffsetAdded) {
+ UINTN FreeOffset;
+ UINTN Offset;
+ UINTN FfsSize;
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ EFI_FFS_FILE_HEADER FreeHeader;
+
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset(&FreeHeader, -1, sizeof(EFI_FFS_FILE_HEADER));
+ }
+ else {
+ memset(&FreeHeader, 0, sizeof(EFI_FFS_FILE_HEADER));
+ }
+
+ FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+ Offset = 0;
+ CurrentFile = NULL;
+ FreeOffset = 0;
+ do {
+ if (FreeOffset == 0 && memcmp(FdBuffer + ImageAddress + (UINTN)ALIGN_POINTER(Offset, 8), &FreeHeader, sizeof(EFI_FFS_FILE_HEADER)) == 0) {
+ //
+ // Offset of free FV space found
+ //
+ FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8);
+ }
+ Status = FvBufFindNextFile(FdBuffer + ImageAddress, &Offset, (VOID **)&CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ break;
+ }
+ else if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (CurrentFile != NULL && CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD &&
+ ReplaceFfs(Fv, InputFfs, CurrentFile)) {
+ *OffsetAdded = (UINT8 *)CurrentFile - (FdBuffer + ImageAddress);
+ return EFI_SUCCESS;
+ }
+ } while (CurrentFile != NULL);
+
+ if (FreeOffset != 0) {
+ if (Fv->FvLength - FreeOffset < FfsSize) {
+ return EFI_ABORTED;
+ }
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ InputFfs->State = (UINT8)~(InputFfs->State);
+ }
+ memcpy(FdBuffer + ImageAddress + FreeOffset, InputFfs, FfsSize);
+ *OffsetAdded = FreeOffset;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+static
+EFI_STATUS
+FindPreviousFile(VOID *Fv, VOID *CurrentFile, VOID **PreFile) {
+ EFI_STATUS Status;
+ VOID *File = NULL;
+ UINTN Offset = 0;
+
+ do {
+ *PreFile = File;
+ Status = FvBufFindNextFile(Fv, &Offset, &File);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ break;
+ }
+ else if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ if (File == CurrentFile) {
+ return EFI_SUCCESS;
+ }
+ } while (CurrentFile != NULL);
+ *PreFile = NULL;
+ return Status;
+}
+
+static
+BOOLEAN
+NeedNewPath(FV_INFORMATION *FvInFd, CHAR8 *FvId, UINT32 FileIndex, BOOLEAN IsAdd) {
+ UINT32 Index;
+
+ Index = 0;
+
+ if (strcmp(FvId, FvInFd->FvName) != 0) {
+ return FALSE;
+ }
+ if (IsAdd) {
+ return TRUE;
+ }
+ if (FvInFd->FfsAttuibutes[FileIndex].FvLevel != 1) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ if (FvInFd->FfsAttuibutes[Index].FvLevel != 1) {
+ continue;
+ }
+ switch (FvInFd->FfsHeader[Index].Type) {
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static UINT32 FindFile(FV_INFORMATION *FvInFd, UINT8 FvLevel, CHAR8 *File, UINT32 *MatchIndex) {
+ UINT32 Index = 0;
+ CHAR16 *UIName;
+ CHAR16 *FfsUIName;
+ UINT32 FileNumber = 0;
+
+ UIName = (CHAR16 *)malloc(_MAX_PATH);
+ if (NULL == UIName) {
+ return 0;
+ }
+ FfsUIName = (CHAR16 *)malloc(_MAX_PATH);
+ if (NULL == FfsUIName) {
+ free(UIName);
+ return 0;
+ }
+ LibAscii2Unicode(File, UIName);
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ //
+ // Compare the New File Name with UI Name of FFS
+ // NOTE: The UI Name is Unicode, but the New File Name is Ascii.
+ //
+ memcpy(FfsUIName, (CHAR16 *)(FvInFd->FfsAttuibutes[Index].UiName), _MAX_PATH);
+
+ if (FvInFd->FfsAttuibutes[Index].UiNameSize > 0 && memcmp(UIName, FfsUIName, FvInFd->FfsAttuibutes[Index].UiNameSize) == 0) {
+ FileNumber += 1;
+ *MatchIndex = Index;
+ if (FileNumber > 1) {
+ break;
+ }
+ }
+
+ }
+ free(UIName);
+ free(FfsUIName);
+
+ return FileNumber;
+}
+
+/**
+ Search the config file from the path list.
+
+ Split the path from env PATH, and then search the cofig
+ file from these paths. The priority is from left to
+ right of PATH string. When met the first Config file, it
+ will break and return the pointer to the full file name.
+
+ @param PathList the pointer to the path list.
+ @param FileName the pointer to the file name.
+
+ @retval The pointer to the file name.
+ @return NULL An error occurred.
+**/
+CHAR8 *
+SearchConfigFromPathList (
+ IN CHAR8 *PathList,
+ IN CHAR8 *FileName
+)
+{
+ CHAR8 *CurDir;
+ CHAR8 *FileNamePath;
+
+ CurDir = NULL;
+ FileNamePath = NULL;
+
+#ifndef __GNUC__
+ CurDir = strtok (PathList,";");
+#else
+ CurDir = strtok (PathList,":");
+#endif
+ while (CurDir != NULL) {
+ FileNamePath = (char *)calloc(
+ strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
+ sizeof(char)
+ );
+ if (FileNamePath == NULL) {
+ return NULL;
+ }
+ sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
+ if (access (FileNamePath, 0) != -1) {
+ return FileNamePath;
+ }
+#ifndef __GNUC__
+ CurDir = strtok(NULL, ";");
+#else
+ CurDir = strtok(NULL, ":");
+#endif
+ free (FileNamePath);
+ FileNamePath = NULL;
+ }
+ return NULL;
+}
+
+UINT32 lenList(FILENode* head){
+ FILENode *p = head;
+ UINT32 sum=0;
+ if(head==NULL) return 0;
+ while(p!=NULL){
+ sum+=1;
+ p=p->Next;
+ }
+ return sum;
+}
+
+void sortList(FILENode* head){
+ UINT32 len = lenList(head);
+ FILENode *p = head;
+ UINT32 i;
+ UINT32 j;
+ if(len==0) return;
+ for(i=1; i<len; ++i){
+ p = head;
+ for(j=0; j<len-i; j++){
+ if(p->SubLevel < p->Next->SubLevel){
+ CHAR8 *FileName = p->FileName;
+ UINT8 tmp = p->SubLevel;
+ p->SubLevel = p->Next->SubLevel;
+ p->Next->SubLevel = tmp;
+ p->FileName = p->Next->FileName;
+ p->Next->FileName = FileName;
+ }
+ p=p->Next;
+ }
+ }
+}
+
+BOOLEAN
+ParseSection (
+ IN EFI_FFS_FILE_HEADER2 *InputFfs
+)
+{
+ BOOLEAN UISectionFlag;
+ UINT32 SectionLength;
+ UINT32 ParsedLength;
+ UINT32 FfsFileSize;
+ UINT8 *Ptr;
+ EFI_SECTION_TYPE Type;
+
+ UISectionFlag = FALSE;
+ Ptr = NULL;
+ SectionLength = 0;
+ ParsedLength = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
+ FfsFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+ while (ParsedLength < FfsFileSize) {
+ Ptr = (UINT8 *)InputFfs + ParsedLength;
+ SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if ((SectionLength == 0xffffff) && (Type == 0xff)) {
+ ParsedLength += 4;
+ continue;
+ }
+ if (Type == EFI_SECTION_USER_INTERFACE) {
+ UISectionFlag = TRUE;
+ break;
+ }
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+ return UISectionFlag;
+
+}
+
+
+/**
+
+ Show the FD image layout information. Only display the modules with UI name.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FvName The FV ID in the FD file;
+ @param[in] ViewFlag Is this call for view or other operate(add/del/replace)
+ @param[in] FdData The Fd data structure store the FD information.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageView (
+ IN CHAR8* FdInName,
+ IN CHAR8* FvName,
+ IN BOOLEAN ViewFlag,
+ IN FIRMWARE_DEVICE **FdData
+)
+{
+ EFI_STATUS Status;
+ EFI_STATUS ErrorStatus;
+ FIRMWARE_DEVICE *LocalFdData;
+ FV_INFORMATION *CurrentFv;
+ FILE *InputFile;
+ UINT32 FvSize;
+ UINTN BytesRead;
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage;
+ UINT32 FfsCount;
+ UINT8 FvCount;
+ CHAR8 *TemDir;
+
+ LocalFdData = NULL;
+ CurrentFv = NULL;
+ FvImage = NULL;
+ TemDir = NULL;
+ FvSize = 0;
+ BytesRead = 0;
+ FfsCount = 0;
+ FvCount = 0;
+ ErrorStatus = EFI_SUCCESS;
+
+ //
+ // Check the FD file name/path.
+ //
+ if (FdInName == NULL) {
+ Error("FMMT", 0, 1001, "Invalid parameter! Please specify <input-binary-file>", FdInName);
+ Usage();
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open the file containing the FV
+ //
+ InputFile = fopen (FdInName, "rb");
+ if (InputFile == NULL) {
+ Error (NULL, 0, 0001, "Error opening the input file", FdInName);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = LibFindFvInFd (InputFile, &LocalFdData);
+
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 1001, "Error while search FV in FD", "");
+ fclose (InputFile);
+ return EFI_ABORTED;
+ }
+
+ CurrentFv = LocalFdData->Fv;
+
+
+ do {
+
+ memset (CurrentFv->FvName, '\0', _MAX_PATH);
+
+ if (FvCount == 0) {
+ sprintf (CurrentFv->FvName, "FV%d", FvCount);
+ } else {
+ sprintf (CurrentFv->FvName, "FV%d", FvCount);
+ }
+
+ //
+ // Determine size of FV
+ //
+ if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
+ Error (NULL, 0, 0003, "error parsing FV image", "%s FD file is invalid", InputFile);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ Status = LibGetFvSize(InputFile, &FvSize);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", InputFile);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET);
+
+
+ FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize);
+
+ if (FvImage == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ BytesRead = fread (FvImage, 1, FvSize, InputFile);
+ if ((unsigned int) BytesRead != FvSize) {
+ Error ("FMMT", 0, 0004, "error reading FvImage from", FdInName);
+ free (FvImage);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ //
+ // Collect FV information each by each.
+ //
+ Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &CurrentFv->EncapData, &FfsCount, &FvCount, ViewFlag, FALSE);
+ if (FvImage != NULL) {
+ free (FvImage);
+ FvImage = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while get information from FV %s", FvName);
+ ErrorStatus = Status;
+ //
+ // If the FV to be parsed error is the same with the input FV in add, replace and delete
+ // operation, abort the program directly.
+ //
+ if ((FvName != NULL) && ((CurrentFv->FvName) != NULL) && !strcmp(CurrentFv->FvName, FvName)) {
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+ }
+
+
+ FfsCount = 0;
+
+ CurrentFv = CurrentFv->FvNext;
+
+ } while (CurrentFv != NULL);
+
+ fclose (InputFile);
+
+ if (ViewFlag) {
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ Status = LibRmDir (TemDir);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ ErrorStatus = Status;
+ }
+ }
+Done:
+ if (!ViewFlag) {
+ *FdData = LocalFdData;
+ } else {
+ LibFmmtFreeFd( LocalFdData);
+ }
+ return ErrorStatus;
+}
+
+/**
+ Add FFS file into a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FileList The FV ID and FFS file Data;
+ @param[in] count The length of FileList;
+ @param[in] FdOutName Name of output FD binary/image file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageAdd(
+ IN CHAR8* FdInName,
+ IN Data *FileList,
+ IN int count,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT8 FvNumInFd;
+ UINT8 FvNumInFdCounter;
+ UINT8 NewAddedFfsLevel;
+ FFS_INFORMATION *OutputFileName;
+ UINT32 Index;
+ UINT32 EndId;
+ UINT8 *FdBuffer;
+ EFI_FIRMWARE_VOLUME_HEADER *Fv;
+ UINT32 FdSize;
+ EFI_FFS_FILE_HEADER2 *InputFfs;
+ UINT32 NewFileSize;
+ UINT64 BaseAddr;
+ UINT32 OffsetAdded;
+ int i;
+ int j;
+ Data *tmp;
+ CHAR8* FvId;
+ CHAR8* NewFile;
+ FILENode *NewFileNode;
+ BOOLEAN HasUISection;
+ HasUISection = FALSE;
+ Index = 0;
+ EndId = 0;
+ NewFvLength = 0;
+ FvNumInFd = 0;
+ FvNumInFdCounter = 0;
+ NewAddedFfsLevel = 0;
+ FdData = NULL;
+ FvInFd = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ OutputFileName = NULL;
+ FvId = NULL;
+ NewFile = NULL;
+
+ FdBuffer = NULL;
+ InputFfs = NULL;
+ BaseAddr = 0;
+ OffsetAdded = 0;
+ FdSize = 0;
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ FdData = tmp->FdData;
+ if (FdData == NULL) {
+ Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
+ if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+ return Status;
+ }
+ if (FdData == NULL) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
+ return EFI_ABORTED;
+ }
+
+ Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
+ return Status;
+ }
+ (FileList + i) -> FdData = FdData;
+ (FileList + i) -> FvInFd = FvInFd;
+ (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ for (j = i + 1; j < count; j++){
+ if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+ continue;
+ }
+ if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+ NewFileNode = (FileList + j)->NewFile;
+ while (NewFileNode ->Next != NULL) {
+ NewFileNode = NewFileNode->Next;
+ }
+ NewFileNode->Next = (FileList + i)->NewFile;
+ (FileList + i)->FvId = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ if ((FileList + i)->FvId == NULL) {
+ continue;
+ }
+ sortList ((FileList + i)-> NewFile);
+ }
+
+ TemDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ if (FdBuffer == NULL) {
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+ return EFI_ABORTED;
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ if (FvId == NULL) {
+ continue;
+ }
+ FdData = tmp->FdData;
+ FvInFd = tmp->FvInFd;
+ NewFileNode =tmp->NewFile;
+
+ NewFile = NewFileNode->FileName;
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ HasUISection = FALSE;
+ HasUISection = ParseSection(InputFfs);
+ if (!HasUISection) {
+ printf ("WARNING: The newly add file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
+ }
+ if (NeedNewPath(FvInFd, FvId, 0, TRUE)) {
+ do {
+ NewFile = NewFileNode->FileName;
+ //
+ // TODO: currently only root FV is handled
+ //
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
+
+ Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0003, "error while adding file", "Not enough space to add FFS");
+ goto FAILED;
+ }
+ //
+ // Calculate base address of Current FV
+ //
+ if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ else {
+ Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ }
+ }
+ NewFileNode = NewFileNode->Next;
+ free (InputFfs);
+ InputFfs = NULL;
+ } while (NewFileNode != NULL);
+ } else {
+ do {
+ NewFile = NewFileNode->FileName;
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ Error ("FMMT", 0, 2000, "error while adding file", "New file name is too long!");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2));
+ if (FvInFd->FfsNumbers == 0) {
+ NewAddedFfsLevel = FvInFd->FfsAttuibutes[0].Level;
+ }
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ if (FvInFd->FfsAttuibutes[Index].IsFvStart == 1) {
+ FvNumInFdCounter++;
+ }
+ if ( FvNumInFdCounter == FvNumInFd && FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
+ NewAddedFfsLevel = FvInFd->FfsAttuibutes[Index].Level;
+ EndId = Index+1;
+ break;
+ }
+ if (FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
+ FvNumInFdCounter--;
+ if (FvNumInFdCounter == 0) {
+ FvNumInFd--;
+ }
+ }
+ }
+
+ //
+ // Add the new file into FV.
+ //
+ FvInFd->FfsNumbers += 1;
+ for (Index = FvInFd->FfsNumbers; Index > EndId; Index--) {
+ FvInFd->FfsAttuibutes[Index] = FvInFd->FfsAttuibutes[Index - 1];
+ }
+ strncpy(FvInFd->FfsAttuibutes[EndId].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[EndId].FfsName[_MAX_PATH - 1] = 0;
+ FvInFd->FfsAttuibutes[EndId].Level = NewAddedFfsLevel;
+ memset (&FvInFd->FfsAttuibutes[EndId].GuidName, '\0', sizeof(EFI_GUID));
+ if (EndId > 0) {
+ FvInFd->FfsAttuibutes[EndId].FvLevel = FvInFd->FfsAttuibutes[EndId - 1].FvLevel;
+ FvInFd->FfsAttuibutes[EndId - 1].IsFvEnd = 0;
+ }
+ FvInFd->FfsAttuibutes[EndId].IsFvEnd = 1;
+ FvInFd->FfsAttuibutes[EndId].IsFvStart = 0;
+ NewFileNode = NewFileNode->Next;
+ } while (NewFileNode != NULL);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+ goto FAILED;
+ }
+
+ NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+ if (NewFvFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+ fseek(NewFvFile,0,SEEK_SET);
+ Buffer = malloc ((size_t)NewFvLength);
+ if (Buffer == NULL) {
+ Status = EFI_ABORTED;
+ fclose(NewFvFile);
+ goto FAILED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+ free (Buffer);
+ Status = EFI_ABORTED;
+ fclose(NewFvFile);
+ goto FAILED;
+ }
+
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+ } else {
+ Error ("FMMT", 0, 0004, "error writing FD file", "The add ffs file is too large.");
+ }
+ fclose(NewFvFile);
+ free(Buffer);
+ }
+ }
+
+ Status = LibRmDir(TemDir);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ goto FAILED;
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+ free(FdBuffer);
+ free(InputFfs);
+ printf ("Create New FD file successfully. \n\nDone! \n");
+ return EFI_SUCCESS;
+
+ FAILED:
+ if (FdBuffer != NULL) {
+ free(FdBuffer);
+ }
+ if (InputFfs != NULL) {
+ free(InputFfs);
+ }
+ return Status;
+}
+
+/**
+Delete a root FV from FD.
+
+@param[in] FdInName Input FD binary/image file name;
+@param[in] FvName FV name;
+@param[in] FdOutName Name of output fd file.
+
+@retval EFI_SUCCESS
+@retval EFI_INVALID_PARAMETER
+@retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageDeleteFv(
+ IN CHAR8* FdInName,
+ IN CHAR8* FvName,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FV_INFORMATION *FvInFd;
+ FILE *NewFdFile;
+ CHAR8 *TemDir;
+
+ UINT8 *FdBuffer = NULL;
+ UINT8 *FdBak = NULL;
+ UINT32 FdSize = 0;
+
+ FIRMWARE_DEVICE *FdData = NULL;
+
+ TemDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ Status = FmmtImageView(FdInName, NULL, FALSE, &FdData);
+ if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+ goto END;
+ }
+ if (FdData == NULL) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+
+ FvInFd = FdData->Fv;
+ while (FvInFd) {
+ if (FvInFd->FvUiName && strcmp(FvInFd->FvUiName, FvName) == 0) {
+ break;
+ }
+ FvInFd = FvInFd->FvNext;
+ }
+ if (!FvInFd) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot find this FV!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ FdBak = FdBuffer;
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot read FD file!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+
+ if (FvInFd->ImageAddress == 0) {
+ FdBuffer = FdBuffer + FvInFd->FvHeader->FvLength;
+ FdSize -= (UINT32)FvInFd->FvHeader->FvLength;
+ } else {
+ if (FvInFd->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset(FdBuffer + FvInFd->ImageAddress, -1, (size_t)FvInFd->FvHeader->FvLength);
+ }
+ else {
+ memset(FdBuffer + FvInFd->ImageAddress, 0, (size_t)FvInFd->FvHeader->FvLength);
+ }
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+
+ Status = LibRmDir(TemDir);
+
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "remove directory failed!");
+ goto END;
+ }
+
+ printf("Create New FD file successfully. \n\nDone! \n");
+END:
+ LibFmmtFreeFd(FdData);
+ free(FdBak);
+ return Status;
+}
+
+/**
+ Delete an FFS file from a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FileList The FV ID and FFS file Data;
+ @param[in] count The length of FileList;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageDelete (
+ IN CHAR8* FdInName,
+ IN Data *FileList,
+ IN int count,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ UINT32 Index;
+ UINT32 FfsFoundFlag;
+ FFS_INFORMATION *OutputFileName;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT8 FvNumInFd;
+ UINT32 Offset;
+ UINT8 *FdBuffer;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ EFI_FFS_FILE_HEADER2 *PreFile;
+ Data *tmp;
+ CHAR8* FvId;
+ CHAR8* DelFile;
+ FILENode *OldFileNode;
+ int i;
+ UINT32 FfsSize;
+ UINT32 FdSize;
+ int j;
+
+ FdSize = 0;
+ Index = 0;
+ NewFvLength = 0;
+ FfsFoundFlag = 0;
+ FdData = NULL;
+ FvInFd = NULL;
+ OutputFileName = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ FvNumInFd = 0;
+ Offset = 0;
+ FdBuffer = NULL;
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ FdData = tmp->FdData;
+ if (FdData == NULL) {
+ Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
+ if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+ return Status;
+ }
+ if (FdData == NULL) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
+ return EFI_ABORTED;
+ }
+
+ Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
+ return Status;
+ }
+ (FileList + i) -> FdData = FdData;
+ (FileList + i) -> FvInFd = FvInFd;
+ (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+ }
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp-> OldFile;
+ do {
+ DelFile = OldFileNode->FileName;
+ if (FvInFd == NULL) {
+ break;
+ }
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+ if (FfsFoundFlag) {
+ if (FfsFoundFlag > 1) {
+ printf("Duplicated file found in this FV, file name: %s\n", DelFile);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
+ return EFI_ABORTED;
+ }
+ OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+ OldFileNode = OldFileNode->Next;
+ } while (OldFileNode != NULL);
+ }
+
+ for (i = 0; i < count; i++) {
+ for (j = i + 1; j < count; j++)
+ {
+ if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+ continue;
+ }
+ if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+ OldFileNode = (FileList + j)->OldFile;
+ while (OldFileNode ->Next != NULL) {
+ OldFileNode = OldFileNode->Next;
+ }
+ OldFileNode->Next = (FileList + i)->OldFile;
+ (FileList + i)->FvId = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ if ((FileList + i)->FvId == NULL) {
+ continue;
+ }
+ sortList ((FileList + i)-> OldFile);
+ }
+
+ TemDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ if (FdBuffer == NULL) {
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while deleting file", "cannot read input file.");
+ return EFI_ABORTED;
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ if (FvId == NULL) {
+ continue;
+ }
+ FdData = tmp->FdData;
+ FvInFd = tmp->FvInFd;
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp->OldFile;
+ DelFile = OldFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+ if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
+ do {
+ DelFile = OldFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+ //
+ // TODO: currently only root FV is handled
+ //
+ Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
+ if (FdBuffer != NULL) {
+ CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
+
+ FfsSize = CalcuFfsSize((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile);
+
+ FindPreviousFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, (VOID **) &PreFile);
+ if (PreFile != NULL && PreFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ FfsSize += (UINT8 *)CurrentFile - (UINT8 *)PreFile;
+ CurrentFile = PreFile;
+ }
+ AddPadFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, FfsSize);
+ }
+ OldFileNode = OldFileNode -> Next;
+ } while (OldFileNode != NULL);
+ } else {
+ do {
+ DelFile = OldFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+
+ if (FfsFoundFlag) {
+ //
+ // Delete this FFS file from Current FV structure.
+ //
+ Status = LibFmmtDeleteFile (FvInFd->FfsAttuibutes[Index].FfsName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+ Error ("FMMT", 0, 0004, "Cannot find the file need to delete", "Please check the name of the file you want to delete!");
+ goto FAILED;
+ }
+
+ memset(FvInFd->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+ FvInFd->FfsAttuibutes[Index].Level = 0xFF;
+
+ //
+ // Since we can avoid to add NULL ffs file, at this time we don't need to decrease the FFS number.
+ // If decrease operation executed, we should adjust the ffs list. It will bring in more complex.
+ //
+ //FvInFd->FfsNumbers -= 1;
+ memset(FvInFd->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+ if (FvInFd->FfsAttuibutes[Index].FvLevel > 1) {
+ for (j = Index - 1; j >= 0; j--) {
+ if (FvInFd->FfsAttuibutes[j].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel - 1) {
+ break;
+ }
+ }
+ if (Index+1 <= FvInFd->FfsNumbers) {
+ if (FvInFd->FfsAttuibutes[Index+1].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel + 1) {
+ for (j = Index+1; j <= (signed)FvInFd->FfsNumbers; j++) {
+ if (FvInFd->FfsAttuibutes[j].FvLevel > FvInFd->FfsAttuibutes[Index].FvLevel) {
+ Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[j].FfsName);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+ return Status;
+ }
+ memset(FvInFd->FfsAttuibutes[j].FfsName, '\0', _MAX_PATH);
+ FvInFd->FfsAttuibutes[j].Level = 0xFF;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ OldFileNode = OldFileNode -> Next;
+
+ }while (OldFileNode != NULL);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+ goto FAILED;
+ }
+
+ NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+ if (NewFvFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+ fseek(NewFvFile,0,SEEK_SET);
+ Buffer = malloc ((size_t)NewFvLength);
+ if (Buffer == NULL) {
+ fclose(NewFvFile);
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+ fclose(NewFvFile);
+ free(Buffer);
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+ free(Buffer);
+ fclose(NewFvFile);
+ }
+ }
+
+ Status = LibRmDir(TemDir);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ goto FAILED;
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+ free(FdBuffer);
+ printf("Create New FD file successfully. \n\nDone! \n");
+ return EFI_SUCCESS;
+
+ FAILED:
+ free(FdBuffer);
+ return Status;
+}
+
+/**
+ Replace the exist FFS file with new one from a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FileList The FV ID and FFS file Data;
+ @param[in] count The length of FileList;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageReplace (
+ IN CHAR8* FdInName,
+ IN Data *FileList,
+ IN int count,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ UINT32 Index;
+ UINT32 FfsFoundFlag;
+ FFS_INFORMATION *OutputFileName;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT32 Offset;
+ UINT8 *FdBuffer;
+ UINT8 FvNumInFd;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ EFI_FIRMWARE_VOLUME_HEADER *Fv;
+ UINT32 FdSize;
+ EFI_FFS_FILE_HEADER2 *InputFfs;
+ UINT32 NewFileSize;
+ UINT32 PadFileSize;
+ UINT64 BaseAddr;
+ UINT32 OffsetAdded;
+ Data *tmp;
+ CHAR8* FvId;
+ CHAR8* OldFile;
+ CHAR8* NewFile;
+ int i;
+ int j;
+ FILENode *OldFileNode;
+ FILENode *NewFileNode;
+ BOOLEAN HasUISection;
+ HasUISection = FALSE;
+ Index = 0;
+ NewFvLength = 0;
+ FfsFoundFlag = 0;
+ FdData = NULL;
+ FvInFd = NULL;
+ OutputFileName = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ Offset = 0;
+ FdBuffer = NULL;
+ InputFfs = NULL;
+ BaseAddr = 0;
+ OffsetAdded = 0;
+ FdSize = 0;
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ FdData = tmp->FdData;
+ if (FdData == NULL){
+ Status = FmmtImageView(FdInName, FvId, FALSE, &FdData);
+ if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ return Status;
+ }
+
+ if (FdData == NULL) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "");
+ return EFI_ABORTED;
+ }
+
+ Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0005, "error while locate FV in FD", "");
+ return Status;
+ }
+ (FileList + i) -> FdData = FdData;
+ (FileList + i) -> FvInFd = FvInFd;
+ (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+ }
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp-> OldFile;
+ NewFileNode = tmp-> NewFile;
+ do {
+ OldFile = OldFileNode -> FileName;
+ NewFile = NewFileNode -> FileName;
+ if (FvInFd == NULL) {
+ break;
+ }
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+
+ if (FfsFoundFlag) {
+ if (FfsFoundFlag > 1) {
+ printf("Duplicated file found in this FV, file name: %s\n", OldFile);
+ return EFI_ABORTED;
+ }
+ //
+ // Replace this FFS file with the new one.
+ // strcpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile);
+ } else {
+ printf ("Could not found the FFS file need to be replaced from FD! file name: %s\n", OldFile);
+ return EFI_ABORTED;
+ }
+ OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+ NewFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+ OldFileNode = OldFileNode->Next;
+ NewFileNode = NewFileNode->Next;
+ } while (OldFileNode != NULL && NewFileNode != NULL);
+ }
+
+ for (i = 0; i < count; i++) {
+ for (j = i + 1; j < count; j++)
+ {
+ if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+ continue;
+ }
+ if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+ OldFileNode = (FileList + j)->OldFile;
+ NewFileNode = (FileList + j)->NewFile;
+ while (OldFileNode->Next != NULL && NewFileNode->Next != NULL) {
+ OldFileNode = OldFileNode->Next;
+ NewFileNode = NewFileNode->Next;
+ }
+ OldFileNode->Next = (FileList + i)->OldFile;
+ NewFileNode->Next = (FileList + i)->NewFile;
+ (FileList + i)->FvId = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ if ((FileList + i)->FvId == NULL) {
+ continue;
+ }
+ sortList ((FileList + i)-> OldFile);
+ sortList ((FileList + i)-> NewFile);
+ }
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ if (FdBuffer == NULL) {
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+ return EFI_ABORTED;
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ if (FvId == NULL) {
+ continue;
+ }
+ FdData = tmp->FdData;
+ FvInFd = tmp->FvInFd;
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp-> OldFile;
+ OldFile = OldFileNode -> FileName;
+ NewFileNode = tmp-> NewFile;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+
+ NewFile = NewFileNode->FileName;
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+ HasUISection = FALSE;
+ HasUISection = ParseSection(InputFfs);
+ if (!HasUISection) {
+ printf ("WARNING: The newly replace file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
+ }
+ if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
+ do {
+ OldFile = OldFileNode -> FileName;
+ NewFile = NewFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+ //
+ // TODO: currently only root FV is handled
+ //
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
+ Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
+ OffsetAdded = FvInFd->FfsAttuibutes[Index].Offset;
+
+ if (!ReplaceFfs(Fv, InputFfs, (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset))) {
+ Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0003, "error while replacing file", "cannot add ffs");
+ goto END;
+ }
+ //
+ // Set original FFS to PAD file
+ //
+ CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset);
+ PadFileSize = CalcuFfsSize(Fv, CurrentFile);
+ AddPadFile(Fv, CurrentFile, PadFileSize);
+ }
+
+ //
+ // Calculate base address of Current FV
+ //
+ if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ else {
+ Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ }
+ }
+ OldFileNode = OldFileNode -> Next;
+ NewFileNode = NewFileNode -> Next;
+ free (InputFfs);
+ InputFfs = NULL;
+ } while (OldFileNode != NULL && NewFileNode!= NULL);
+ } else {
+ do {
+ OldFile = OldFileNode->FileName;
+ NewFile = NewFileNode->FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+ //
+ // Replace this FFS file with the new one.
+ //
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ Error ("FMMT", 0, 2000, "error while replacing file", "New file name is too long!");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+ strncpy(FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
+ OldFileNode = OldFileNode->Next;
+ NewFileNode = NewFileNode->Next;
+ } while (OldFileNode != NULL && NewFileNode != NULL);
+ Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+ free (FdBuffer);
+ return Status;
+ }
+
+ NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+ if (NewFvFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+ fseek(NewFvFile,0,SEEK_SET);
+ Buffer = malloc ((size_t)NewFvLength);
+ if (Buffer == NULL) {
+ fclose(NewFvFile);
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+ free(Buffer);
+ free (FdBuffer);
+ fclose(NewFvFile);
+ return EFI_ABORTED;
+ }
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+ }else {
+ Error ("FMMT", 0, 0004, "error writing FD file", "The replace ffs file is too large.");
+ }
+ free(Buffer);
+ fclose(NewFvFile);
+ }
+ }
+
+ Status = LibRmDir(TemDir);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+ free(FdBuffer);
+ printf("Create New FD file successfully. \n\nDone! \n");
+ return EFI_SUCCESS;
+
+ END:
+ if (FdBuffer != NULL) {
+ free(FdBuffer);
+ }
+ if (InputFfs != NULL) {
+ free(InputFfs);
+ }
+ return EFI_ABORTED;
+}
+
+/**
+
+The main entry of FMMT.
+
+@param argc The number of input parameters.
+@param *argv[] The array pointer to the parameters.
+
+@retval 0 The application exited normally.
+@retval 1 An error occurred.
+
+**/
+int main(
+ int Argc,
+ char *Argv[]
+)
+{
+ EFI_STATUS Status;
+ CHAR8 *TemDir;
+ FILE *CheckFileExist;
+ CHAR8 *InFilePath;
+ CHAR8 FullGuidToolDefinition[_MAX_PATH];
+ CHAR8 *FileName;
+ UINTN FileNameIndex;
+ CHAR8 *PathList;
+ UINTN EnvLen;
+ CHAR8 *NewPathList;
+ Data *FileData;
+ int index;
+ int count;
+ int exist;
+ int j;
+ FILENode *p;
+ FILENode *q;
+
+ p = NULL;
+ q = NULL;
+ TemDir = NULL;
+ CheckFileExist = NULL;
+ PathList = NULL;
+ NewPathList = NULL;
+ EnvLen = 0;
+ count = 0;
+ exist = -1;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return 1;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ //
+ // Print utility header
+ //
+ printf ("Intel(R) %s. Version %d.%d, %s. %s.\n",
+ UTILITY_NAME,
+ UTILITY_MAJOR_VERSION,
+ UTILITY_MINOR_VERSION,
+ __DATE__,
+ __BUILD_VERSION
+ );
+
+ //
+ // Should have more than 1 arguments.
+ //
+ if (Argc <= 1) {
+ Usage();
+ return 1;
+ }
+
+ //
+ // Workaroud: the first call to this function
+ // returns a file name ends with dot
+ //
+#ifndef __GNUC__
+ tmpnam (NULL);
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ close(Fdtmp);
+#endif
+
+ //
+ // Save, skip filename arg
+ //
+ FileName = Argv[0];
+ Argc--;
+ Argv++;
+
+ //
+ // Get the same path with the application itself
+ //
+ if (strlen (FileName) > _MAX_PATH - 1) {
+ Error ("FMMT", 0, 2000, "Parameter: The input filename is too long", NULL);
+ return 1;
+ }
+ strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1);
+ FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+ FileNameIndex = strlen (FullGuidToolDefinition);
+ while (FileNameIndex != 0) {
+ FileNameIndex --;
+ if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+ FullGuidToolDefinition[FileNameIndex] = 0;
+ break;
+ }
+ }
+ //
+ // Build the path list for Config file scan. The priority is below.
+ // 1. Scan the current path
+ // 2. Scan the same path with the application itself
+ // 3. Scan the current %PATH% of OS environment
+ // 4. Use the build-in default configuration
+ //
+ PathList = getenv("PATH");
+ if (PathList == NULL) {
+ Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
+ return 1;
+ }
+ EnvLen = strlen(PathList);
+ NewPathList = (char *)calloc(
+ strlen (".")
+ + strlen (";")
+ + strlen (FullGuidToolDefinition)
+ + strlen (";")
+ + EnvLen
+ + 1,
+ sizeof(char)
+ );
+ if (NewPathList == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ PathList = NULL;
+ free (PathList);
+ return 1;
+ }
+#ifndef __GNUC__
+ sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList);
+#else
+ sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList);
+#endif
+ PathList = NULL;
+ free (PathList);
+
+ //
+ // Load Guid Tools definition
+ //
+ InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
+ free (NewPathList);
+ if (InFilePath != NULL) {
+ printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath);
+ mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+ free (InFilePath);
+ } else {
+ //
+ // Use the pre-defined standard guided tools.
+ //
+ printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n");
+ mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
+ }
+
+ if ((strcmp(Argv[0], "-v") == 0) || (strcmp(Argv[0], "-V") == 0)) {
+ //
+ // View the FD binary image information.
+ //
+ if (Argc <= 1) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage ();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ Status = FmmtImageView(Argv[1], NULL, TRUE, NULL);
+
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while view the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+
+ } else if ((strcmp(Argv[0], "-d") == 0) || (strcmp(Argv[0], "-D") == 0)) {
+ //
+ // Delete some named FFS file from FD binary image.
+ //
+ if (!((Argc == 4) || ((Argc - 3) % 2 == 0))) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage ();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ if ((Argc - 3) % 2 == 0) {
+ FileData = malloc(sizeof (Data) * (Argc - 3)/2);
+ if (FileData == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return 1;
+ }
+ for(index = 0; index < (Argc - 3)/2; index ++) {
+ p = malloc(sizeof (FILENode));
+ if (p == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ return 1;
+ }
+ p -> FileName = Argv[3 + index * 2];
+ p -> SubLevel = 0;
+ exist = -1;
+ for (j = 0; j < count; j ++) {
+ if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
+ exist = j;
+ break;
+ }
+ }
+ if (exist >= 0) {
+ p -> Next = (FileData + j) -> OldFile;
+ (FileData + j) -> OldFile = p;
+ } else {
+ (FileData + count) -> NewFile = NULL;
+ (FileData + count) -> FdData = NULL;
+ (FileData + count) -> FvLevel = 0;
+ (FileData + count) -> FvInFd = NULL;
+ (FileData + count) -> FvId = Argv[2 + index * 2];;
+ (FileData + count) -> OldFile = p;
+ p -> Next = NULL;
+ count ++;
+ }
+ }
+
+ if (count <= 0) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ }
+ for (index = 0; index < count; index ++) {
+ for (j = index + 1; j < count; j ++) {
+ if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+ CHAR8 *tmp = (FileData + index)->FvId;
+ FILENode *t = (FileData + index)->OldFile;
+ (FileData + index)->FvId = (FileData + j)->FvId;
+ (FileData + index)-> OldFile = (FileData + j)->OldFile;
+ (FileData + j)-> OldFile = t;
+ (FileData + j)-> FvId = tmp;
+ }
+ }
+ }
+
+ //
+ // Delete some FFS file
+ //
+ Status = FmmtImageDelete(Argv[1], FileData, count, Argv[Argc-1]);
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index) ->NewFile != NULL) {
+ free ((FileData + index)->NewFile);
+ (FileData + index)->NewFile = NULL;
+ }
+ if ((FileData + index)->OldFile != NULL) {
+ free ((FileData + index)->OldFile);
+ (FileData + index)->OldFile = NULL;
+ }
+ }
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->FdData != NULL) {
+ LibFmmtFreeFd ((FileData + index)->FdData);
+ }
+ }
+ free (FileData);
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while delete some named ffs file from the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+ } else {
+ //
+ // Delete FV
+ //
+ Status = FmmtImageDeleteFv(Argv[1], Argv[2], Argv[3]);
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while delete the entire FV from the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+ }
+
+ } else if ((strcmp(Argv[0], "-a") == 0) || (strcmp(Argv[0], "-A") == 0)) {
+ //
+ // Add some named FFS file into FD binary image.
+ //
+ if ((Argc - 3 ) % 2 != 0) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage ();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ //
+ // Check whether the new added file exist or not.
+ //
+ for (index = 1; index < (Argc - 1) / 2; index ++) {
+ CheckFileExist = fopen(Argv[2 * index + 1], "rb");
+ if (CheckFileExist == NULL) {
+ Error("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[2 * index + 1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+ }
+
+ FileData = malloc(sizeof (Data) * (Argc - 3)/2);
+ if (FileData == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return 1;
+ }
+ for(index = 0; index < (Argc - 3)/2; index ++) {
+ p = malloc(sizeof (FILENode));
+ if (p == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ return 1;
+ }
+ p -> FileName = Argv[3 + index * 2];
+ p -> SubLevel = 0;
+ exist = -1;
+ for (j = 0; j < count; j ++) {
+ if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
+ exist = j;
+ break;
+ }
+ }
+ if (exist >= 0) {
+ p -> Next = (FileData + j) -> NewFile;
+ (FileData + j) -> NewFile = p;
+ } else {
+ (FileData + count) -> OldFile = NULL;
+ (FileData + count) -> FdData = NULL;
+ (FileData + count) -> FvLevel = 0;
+ (FileData + count) -> FvInFd = NULL;
+ (FileData + count) -> FvId = Argv[2 + index * 2];
+ (FileData + count) -> NewFile = p;
+ p -> Next = NULL;
+ count ++;
+ }
+ }
+
+ if (count <= 0) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ }
+
+ for (index = 0; index < count; index ++) {
+ for (j = index + 1; j < count; j ++) {
+ if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+ CHAR8 *tmp = (FileData + index)->FvId;
+ FILENode *temp = (FileData + index)->NewFile;
+ (FileData + index)->FvId = (FileData + j)->FvId;
+ (FileData + index)-> NewFile = (FileData + j)->NewFile;
+ (FileData + j)-> NewFile = temp;
+ (FileData + j)-> FvId = tmp;
+ }
+ }
+ }
+
+ Status = FmmtImageAdd(Argv[1], FileData, count, Argv[Argc-1]);
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->NewFile != NULL) {
+ free ((FileData + index)->NewFile);
+ (FileData + index)->NewFile = NULL;
+ }
+ if ((FileData + index)->OldFile != NULL) {
+ free ((FileData + index)->OldFile);
+ (FileData + index)->OldFile = NULL;
+ }
+ }
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->FdData != NULL) {
+ LibFmmtFreeFd ((FileData + index)->FdData);
+ }
+ }
+ free (FileData);
+
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while add some named ffs file into the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+
+ } else if ((strcmp(Argv[0], "-r") == 0) || (strcmp(Argv[0], "-R") == 0)) {
+ //
+ // Replace some named FFS file in the FD binary.
+ //
+ if ((Argc - 3) % 3 != 0) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ //
+ // Check whether the new FFS file exist or not.
+ //
+ for (index = 1; index < Argc/3; index ++) {
+ CheckFileExist = fopen(Argv[3 * index + 1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[3 * index + 1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+ }
+
+ FileData = malloc(sizeof (Data) * (Argc - 3)/3);
+ if (FileData == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return 1;
+ }
+ for(index = 0; index < (Argc - 3)/3; index ++) {
+ p = malloc(sizeof (FILENode)); //p for old file
+ if (p == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ return 1;
+ }
+ q = malloc(sizeof (FILENode)); //q for new file
+ if (q == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ free (p);
+ return 1;
+ }
+ p -> FileName = Argv[3 + index * 3];
+ q -> FileName = Argv[4 + index * 3];
+ p -> SubLevel = 0;
+ q -> SubLevel = 0;
+ exist = -1;
+ for (j = 0; j < count; j ++) {
+ if ((strcmp(Argv[2 + index * 3], (FileData + j) -> FvId) == 0)) {
+ exist = j;
+ break;
+ }
+ }
+ if (exist >= 0) {
+ p -> Next = (FileData + j) -> OldFile;
+ (FileData + j) -> OldFile = p;
+ q -> Next = (FileData + j) -> NewFile;
+ (FileData + j) -> NewFile = q;
+ } else {
+ (FileData + count) -> FdData = NULL;
+ (FileData + count) -> FvLevel = 0;
+ (FileData + count) -> FvInFd = NULL;
+ (FileData + count) -> FvId = Argv[2 + index * 3];;
+ (FileData + count) -> OldFile = p;
+ (FileData + count) -> NewFile = q;
+ p -> Next = NULL;
+ q -> Next = NULL;
+ count ++;
+ }
+ }
+
+ if (count <= 0) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ }
+ for (index = 0; index < count; index ++) {
+ for (j = index + 1; j < count; j ++) {
+ if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+ CHAR8 *tmp = (FileData + index)->FvId;
+ FILENode *Old = (FileData + index)->OldFile;
+ FILENode *New = (FileData + index)->NewFile;
+ (FileData + index)->FvId = (FileData + j)->FvId;
+ (FileData + index)->OldFile = (FileData + j)->OldFile;
+ (FileData + index)->NewFile = (FileData + j)->NewFile;
+ (FileData + j)->OldFile = Old;
+ (FileData + j)->NewFile = New;
+ (FileData + j)->FvId = tmp;
+ }
+ }
+ }
+
+ Status = FmmtImageReplace(Argv[1], FileData, count, Argv[Argc-1]);
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->NewFile != NULL) {
+ free ((FileData + index)->NewFile);
+ (FileData + index)->NewFile = NULL;
+ }
+ if ((FileData + index)->OldFile != NULL) {
+ free ((FileData + index)->OldFile);
+ (FileData + index)->OldFile = NULL;
+ }
+ }
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->FdData != NULL) {
+ LibFmmtFreeFd ((FileData + index)->FdData);
+ }
+ }
+ free (FileData);
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while replace the named ffs file in the FD image file with the new ffs file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+
+ } else if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
+ (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
+ //
+ // print help information to user.
+ //
+ Usage();
+
+ } else {
+ //
+ // Invalid parameter.
+ //
+ printf("\n");
+ Error("FMMT", 0, 1001, "Invalid parameter", Argv[0]);
+ Usage();
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/BaseTools/Source/C/FMMT/FmmtLib.c b/BaseTools/Source/C/FMMT/FmmtLib.c
new file mode 100644
index 0000000000..f87042114b
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FmmtLib.c
@@ -0,0 +1,5051 @@
+/** @file
+
+ Library to parse and generate FV image.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FirmwareModuleManagement.h"
+
+#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
+ ( \
+ (BOOLEAN) ( \
+ (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
+ ) \
+ )
+
+CHAR8 mFirmwareFileSystem2Guid[16] = {0x78, 0xE5, 0x8C, 0x8C, 0x3D, 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3};
+
+CHAR8 mFirmwareFileSystem3Guid[16] = {0x7A, 0xC0, 0x73, 0x54, 0xCB, 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A };
+
+EFI_GUID mEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
+extern CHAR8* mGuidToolDefinition;
+
+static CHAR8 *mSectionTypeName[] = {
+ NULL, // 0x00 - reserved
+ "EFI_SECTION_COMPRESSION", // 0x01
+ "EFI_SECTION_GUID_DEFINED", // 0x02
+ NULL, // 0x03 - reserved
+ NULL, // 0x04 - reserved
+ NULL, // 0x05 - reserved
+ NULL, // 0x06 - reserved
+ NULL, // 0x07 - reserved
+ NULL, // 0x08 - reserved
+ NULL, // 0x09 - reserved
+ NULL, // 0x0A - reserved
+ NULL, // 0x0B - reserved
+ NULL, // 0x0C - reserved
+ NULL, // 0x0D - reserved
+ NULL, // 0x0E - reserved
+ NULL, // 0x0F - reserved
+ "EFI_SECTION_PE32", // 0x10
+ "EFI_SECTION_PIC", // 0x11
+ "EFI_SECTION_TE", // 0x12
+ "EFI_SECTION_DXE_DEPEX", // 0x13
+ "EFI_SECTION_VERSION", // 0x14
+ "EFI_SECTION_USER_INTERFACE", // 0x15
+ "EFI_SECTION_COMPATIBILITY16", // 0x16
+ "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17
+ "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18
+ "EFI_SECTION_RAW", // 0x19
+ NULL, // 0x1A
+ "EFI_SECTION_PEI_DEPEX", // 0x1B
+ "EFI_SECTION_SMM_DEPEX" // 0x1C
+};
+
+
+static CHAR8 *mFfsFileType[] = {
+ NULL, // 0x00
+ "EFI_FV_FILETYPE_RAW", // 0x01
+ "EFI_FV_FILETYPE_FREEFORM", // 0x02
+ "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03
+ "EFI_FV_FILETYPE_PEI_CORE", // 0x04
+ "EFI_FV_FILETYPE_DXE_CORE", // 0x05
+ "EFI_FV_FILETYPE_PEIM", // 0x06
+ "EFI_FV_FILETYPE_DRIVER", // 0x07
+ "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
+ "EFI_FV_FILETYPE_APPLICATION", // 0x09
+ "EFI_FV_FILETYPE_SMM", // 0x0A
+ "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
+ "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C
+ "EFI_FV_FILETYPE_SMM_CORE" // 0x0D
+ };
+
+static CHAR8 *mGuidSectionAttr[] = {
+ "NONE", // 0x00
+ "PROCESSING_REQUIRED", // 0x01
+ "AUTH_STATUS_VALID" // 0x02
+};
+
+static EFI_GUID mFvUiGuid = {
+ 0xA67DF1FA, 0x8DE8, 0x4E98, {
+ 0xAF, 0x09, 0x4B, 0xDF, 0x2E, 0xFF, 0xBC, 0x7C
+ }
+};
+
+
+/**
+ Generate the unique template filename.
+**/
+CHAR8 *
+GenTempFile (
+ VOID
+ )
+{
+ CHAR8 *TemString;
+ TemString = NULL;
+#ifndef __GNUC__
+ TemString = CloneString (tmpnam (NULL));
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ TemString = CloneString(tmp);
+ close(Fdtmp);
+#endif
+ return TemString;
+}
+
+static
+EFI_STATUS
+LibExtractFvUiName(CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader, CHAR8 **FvUiName)
+{
+ UINT8 *ExtEnd;
+ UINT32 ExtDataSize;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntry;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *GuidEntry;
+
+
+ ExtEnd = (UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize;
+ ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(FvExtHeader + 1);
+ while ((UINT8 *)ExtEntry < ExtEnd) {
+ //
+ // GUID type EXT
+ //
+ if (ExtEntry->ExtEntryType == 0x0002) {
+ GuidEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *)ExtEntry;
+ if (memcmp(&GuidEntry->FormatType, &mFvUiGuid, sizeof(EFI_GUID)) == 0) {
+ ExtDataSize = ExtEntry->ExtEntrySize - (sizeof(EFI_GUID)+sizeof(*ExtEntry));
+ *FvUiName = malloc(ExtDataSize + 1);
+ if (*FvUiName != NULL) {
+ memcpy(*FvUiName, (UINT8 *)GuidEntry + sizeof(EFI_GUID)+sizeof(*ExtEntry), ExtDataSize);
+ (*FvUiName)[ExtDataSize] = '\0';
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtEntry + ExtEntry->ExtEntrySize);
+ }
+ return EFI_NOT_FOUND;
+}
+
+FV_INFORMATION *
+LibInitializeFvStruct (
+ FV_INFORMATION *Fv
+)
+{
+ UINT32 Index;
+
+ if (Fv == NULL) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index ++) {
+ memset (Fv->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+ memset (Fv->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+ memset (&Fv->FfsAttuibutes[Index].GuidName, '\0', sizeof(EFI_GUID));
+ Fv->FfsAttuibutes[Index].UiNameSize = 0;
+ Fv->FfsAttuibutes[Index].IsLeaf = TRUE;
+ Fv->FfsAttuibutes[Index].Level = 0xFF;
+ Fv->FfsAttuibutes[Index].TotalSectionNum = 0;
+ Fv->FfsAttuibutes[Index].Depex = NULL;
+ Fv->FfsAttuibutes[Index].DepexLen = 0;
+ Fv->FfsAttuibutes[Index].IsHandle = FALSE;
+ Fv->FfsAttuibutes[Index].IsFvStart = FALSE;
+ Fv->FfsAttuibutes[Index].IsFvEnd = FALSE;
+ }
+
+ Fv->EncapData = NULL;
+ Fv->FvNext = NULL;
+ Fv->ChildFvFFS = NULL;
+ Fv->FvLevel = 0;
+ Fv->MulFvLevel = 1;
+ strcpy(Fv->AlignmentStr,"8");
+ return Fv;
+}
+
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+)
+{
+ FIRMWARE_DEVICE *LocalFdData;
+ UINT16 Index;
+ CHAR8 Ffs2Guid[16];
+ CHAR8 SignatureCheck[5] = "";
+ CHAR8 Signature[5] = "_FVH";
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *NewFoundFv;
+ BOOLEAN FirstMatch;
+ UINT32 FdSize;
+ UINT16 FvCount;
+ UINT8 *FdBuffer;
+ UINT8 *FdBufferEnd;
+ UINT8 *FdBufferOri;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+
+ CurrentFv = NULL;
+ NewFoundFv = NULL;
+ FdBuffer = NULL;
+ FdBufferOri = NULL;
+ FirstMatch = TRUE;
+ Index = 0;
+ FdSize = 0;
+ FvCount = 0;
+ LocalFdData = NULL;
+
+ if (InputFile == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input file", "");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Find each FVs in the FD
+ //
+
+ fseek(InputFile,0,SEEK_SET);
+ fseek(InputFile,0,SEEK_END);
+
+ FdSize = ftell(InputFile);
+
+ fseek(InputFile,0,SEEK_SET);
+ //
+ // Create an FD structure to store useful information.
+ //
+ LocalFdData = (FIRMWARE_DEVICE *) malloc (sizeof (FIRMWARE_DEVICE));
+ if (LocalFdData == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ LocalFdData->Fv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION));
+ if (LocalFdData->Fv == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LibInitializeFvStruct (LocalFdData->Fv);
+
+ //
+ // Readout the FD file data to buffer.
+ //
+ FdBuffer = malloc (FdSize);
+
+ if (FdBuffer == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (FdBuffer, 1, FdSize, InputFile) != FdSize) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Read FD file error!");
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ FdBufferOri = FdBuffer;
+ FdBufferEnd = FdBuffer + FdSize;
+
+ while (FdBuffer <= FdBufferEnd - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FdBuffer;
+ //
+ // Copy 4 bytes of fd data to check the _FVH signature
+ //
+ memcpy (SignatureCheck, &FvHeader->Signature, 4);
+
+ if (strncmp(SignatureCheck, Signature, 4) == 0){
+ //
+ // Still need to determine the FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER equal to
+ // EFI_FIRMWARE_FILE_SYSTEM2_GUID or EFI_FIRMWARE_FILE_SYSTEM3_GUID.
+ // Turn back 28 bytes to find the GUID.
+ //
+ memcpy (Ffs2Guid, &FvHeader->FileSystemGuid, 16);
+
+ //
+ // Compare GUID.
+ //
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem2Guid[Index]) {
+ break;
+ }
+ }
+ if (Index != 16) {
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem3Guid[Index]) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Here we found an FV.
+ //
+ if ((Index == 16) && ((FdBuffer + FvHeader->FvLength) <= FdBufferEnd)) {
+ if (FirstMatch) {
+ LocalFdData->Fv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri);
+ CurrentFv = LocalFdData->Fv;
+ CurrentFv->FvNext = NULL;
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(CurrentFv->FvName, "FV%d", FvCount);
+
+ FirstMatch = FALSE;
+ } else {
+ NewFoundFv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION));
+ if (NewFoundFv == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LibInitializeFvStruct (NewFoundFv);
+
+ //
+ // Need to turn back 0x2c bytes
+ //
+ NewFoundFv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri);
+
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(NewFoundFv->FvName, "FV%d", FvCount);
+
+ //
+ // Value it to NULL for found FV usage.
+ //
+ NewFoundFv->FvNext = NULL;
+ CurrentFv->FvNext = NewFoundFv;
+
+ //
+ // Make the CurrentFv point to next FV.
+ //
+ CurrentFv = CurrentFv->FvNext;
+ }
+
+ FvCount ++;
+ FdBuffer = FdBuffer + FvHeader->FvLength;
+ } else {
+ FdBuffer ++;
+ }
+
+ } else {
+ FdBuffer ++;
+ }
+ }
+
+ LocalFdData->Size = FdSize;
+
+ *FdData = LocalFdData;
+
+ free (FdBufferOri);
+
+ return EFI_SUCCESS;
+}
+
+UINTN
+GetFreeOffset (
+ IN VOID *InputFv
+)
+{
+ UINTN FreeOffset;
+ UINTN Offset;
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+
+ Offset = 0;
+ CurrentFile = NULL;
+ FreeOffset = 0;
+ do {
+ FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8);
+ Status = FvBufFindNextFile(InputFv, &Offset, (VOID **)&CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ break;
+ }
+ else if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } while (CurrentFile != NULL);
+
+ return FreeOffset;
+}
+
+/*
+ Construct a set of blank chars based on the number.
+
+ @param[in] Count The number of blank chars.
+
+ @return A string contained the blank chars.
+
+*/
+CHAR8 *
+LibConstructBlankChar (
+ IN UINT8 Count
+)
+{
+ CHAR8 *RetStr;
+ UINT8 Index;
+
+ Index = 0;
+ RetStr = NULL;
+
+ RetStr = (CHAR8 *) malloc (Count +1);
+
+ if (RetStr == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return NULL;
+ }
+
+ memset (RetStr , '\0', Count + 1);
+
+ for (Index=0; Index <= Count -1; Index ++) {
+ RetStr[Index] = ' ';
+ }
+
+ return RetStr;
+
+}
+
+/**
+
+ This function determines the size of the FV and the erase polarity. The
+ erase polarity is the FALSE value for file state.
+
+
+ @param[in ] InputFile The file that contains the FV image.
+ @param[out] FvSize The size of the FV.
+ @param[out] ErasePolarity The FV erase polarity.
+
+ @return EFI_SUCCESS Function completed successfully.
+ @return EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
+ @return EFI_ABORTED The function encountered an error.
+
+**/
+EFI_STATUS
+LibReadFvHeader (
+ IN VOID *InputFv,
+ IN BOOLEAN ViewFlag,
+ IN UINT8 FvLevel,
+ IN UINT8 FvCount,
+ IN CHAR8 *FvName
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader;
+ CHAR8 *BlankSpace;
+ CHAR8 *FvUiName;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+ BlankSpace = NULL;
+ FvUiName = NULL;
+
+ //
+ // Check input parameters
+ //
+ if (InputFv == NULL) {
+ Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Read the header
+ //
+ VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) InputFv;
+
+
+ BlankSpace = LibConstructBlankChar((FvLevel)*2);
+
+ if (BlankSpace == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+
+ if (ViewFlag) {
+ if ((FvLevel -1) == 0) {
+ printf ("\n%s :\n", FvName);
+ } else {
+ printf ("%sChild FV named FV%d of %s\n", BlankSpace, FvCount, FvName);
+ }
+ }
+
+ //
+ // Print FV header information
+ //
+ if (ViewFlag) {
+ printf ("\n%sAttributes: %X\n", BlankSpace, (unsigned) VolumeHeader->Attributes);
+ printf ("%sTotal Volume Size: 0x%08X\n", BlankSpace, (unsigned) VolumeHeader->FvLength);
+ printf ("%sFree Volume Size: 0x%08X\n", BlankSpace, (unsigned) (VolumeHeader->FvLength - GetFreeOffset(InputFv)));
+ }
+
+ if (ViewFlag && VolumeHeader->ExtHeaderOffset != 0) {
+ FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)VolumeHeader + VolumeHeader->ExtHeaderOffset);
+ printf("%sFvNameGuid: %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+ BlankSpace,
+ FvExtHeader->FvName.Data1,
+ FvExtHeader->FvName.Data2,
+ FvExtHeader->FvName.Data3,
+ FvExtHeader->FvName.Data4[0],
+ FvExtHeader->FvName.Data4[1],
+ FvExtHeader->FvName.Data4[2],
+ FvExtHeader->FvName.Data4[3],
+ FvExtHeader->FvName.Data4[4],
+ FvExtHeader->FvName.Data4[5],
+ FvExtHeader->FvName.Data4[6],
+ FvExtHeader->FvName.Data4[7]);
+ LibExtractFvUiName(FvExtHeader, &FvUiName);
+ if (FvUiName != NULL && FvLevel == 1) {
+ printf("%sFV UI Name: %s\n\n", BlankSpace, FvUiName);
+ }
+ free(FvUiName);
+ }
+ free (BlankSpace);
+ return EFI_SUCCESS;
+}
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+
+ UINTN BytesRead;
+ UINT32 Size;
+ EFI_FV_BLOCK_MAP_ENTRY BlockMap;
+
+ BytesRead = 0;
+ Size = 0;
+
+ if (InputFile == NULL || FvSize == NULL) {
+ Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), SEEK_CUR);
+ do {
+ fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+
+ if (BlockMap.NumBlocks != 0) {
+ Size += BlockMap.NumBlocks * BlockMap.Length;
+ }
+ } while (!(BlockMap.NumBlocks == 0 && BlockMap.Length == 0));
+
+
+ *FvSize = Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Clears out all files from the Fv buffer in memory
+
+ @param[in] Fv - Address of the Fv in memory
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+FvBufGetSize (
+ IN VOID *Fv,
+ OUT UINTN *Size
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FV_BLOCK_MAP_ENTRY *blk;
+
+ *Size = 0;
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ blk = hdr->BlockMap;
+
+ while (blk->Length != 0 || blk->NumBlocks != 0) {
+ *Size = *Size + (blk->Length * blk->NumBlocks);
+ if (*Size >= 0x40000000) {
+ //
+ // If size is greater than 1GB, then assume it is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+ blk++;
+ }
+
+ if (*Size == 0) {
+ //
+ // If size is 0, then assume the volume is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Generate the leaf FFS files.
+
+*/
+EFI_STATUS
+LibGenFfsFile (
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ErasePolarity
+)
+{
+ UINT32 FfsFileSize;
+ CHAR8 *FfsFileName;
+ FILE *FfsFile;
+ CHAR8 *TempDir;
+
+
+ FfsFileSize = 0;
+ FfsFileName = NULL;
+ FfsFile = NULL;
+ TempDir = NULL;
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1);
+
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ FfsFileName = (CHAR8 *) malloc (_MAX_PATH);
+ if (FfsFileName == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ memset (FfsFileName, '\0', _MAX_PATH);
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ sprintf (
+ (CHAR8 *)FfsFileName,
+ "%s%cNum%d-%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X-Level%d",
+ TempDir,
+ OS_SEP,
+ *FfsCount,
+ (unsigned) CurrentFile->Name.Data1,
+ CurrentFile->Name.Data2,
+ CurrentFile->Name.Data3,
+ CurrentFile->Name.Data4[0],
+ CurrentFile->Name.Data4[1],
+ CurrentFile->Name.Data4[2],
+ CurrentFile->Name.Data4[3],
+ CurrentFile->Name.Data4[4],
+ CurrentFile->Name.Data4[5],
+ CurrentFile->Name.Data4[6],
+ CurrentFile->Name.Data4[7],
+ Level
+ );
+
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].FfsName, FfsFileName, strlen(FfsFileName));
+ memcpy (&CurrentFv->FfsAttuibutes[*FfsCount].GuidName, &CurrentFile->Name, sizeof(EFI_GUID));
+ //
+ // Update current FFS files file state.
+ //
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ FfsFile = fopen (FfsFileName, "wb+");
+ if (FfsFile == NULL) {
+ Error ("FMMT", 0, 0003, "error writing FFS file", "cannot Create a new ffs file.");
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) != FfsFileSize) {
+ Error ("FMMT", 0, 0004, "error writing FFS file", "cannot Create a new ffs file.");
+ fclose(FfsFile);
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ fclose(FfsFile);
+ free(FfsFileName);
+ FfsFileName = NULL;
+
+ CurrentFv->FfsNumbers = *FfsCount;
+
+ *FfsCount += 1;
+
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+Unicode2AsciiString (
+ IN CHAR16 *Source,
+ OUT CHAR8 *Destination
+ )
+ /*++
+
+ Routine Description:
+
+ Convert a null-terminated unicode string to a null-terminated ascii string.
+
+ Arguments:
+
+ Source - The pointer to the null-terminated input unicode string.
+ Destination - The pointer to the null-terminated output ascii string.
+
+ Returns:
+
+ N/A
+
+ --*/
+{
+ while (*Source != '\0') {
+ *(Destination++) = (CHAR8) *(Source++);
+ }
+ //
+ // End the ascii with a NULL.
+ //
+ *Destination = '\0';
+}
+
+
+/**
+
+ Parses EFI Sections, if the view flag turn on, then will collect FFS section information
+ and extract FFS files.
+
+ @param[in] SectionBuffer - Buffer containing the section to parse.
+ @param[in] BufferLength - Length of SectionBuffer
+ @param[in, out] CurrentFv
+ @param[in] FvName
+ @param[in] CurrentFile
+ @param[in] Level
+ @param[in, out] FfsCount
+ @param[in] ViewFlag
+ @param[in] ErasePolarity
+
+ @retval EFI_SECTION_ERROR - Problem with section parsing.
+ (a) compression errors
+ (b) unrecognized section
+ @retval EFI_UNSUPPORTED - Do not know how to parse the section.
+ @retval EFI_SUCCESS - Section successfully parsed.
+ @retval EFI_OUT_OF_RESOURCES - Memory allocation failed.
+
+--*/
+EFI_STATUS
+LibParseSection (
+ UINT8 *SectionBuffer,
+ UINT32 BufferLength,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ UINT8 Level,
+ ENCAP_INFO_DATA **CurrentFvEncapData,
+ UINT8 FfsLevel,
+ UINT32 *FfsCount,
+ UINT8 *FvCount,
+ BOOLEAN ViewFlag,
+ BOOLEAN ErasePolarity,
+ BOOLEAN *IsFfsGenerated
+ )
+{
+ UINT32 ParsedLength;
+ UINT8 *Ptr;
+ UINT32 SectionLength;
+ UINT32 UiSectionLength;
+ EFI_SECTION_TYPE Type;
+ EFI_STATUS Status;
+ CHAR8 *ExtractionTool;
+ CHAR8 *ToolInputFile;
+ CHAR8 *ToolOutputFile;
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ UINT8 *ToolOutputBuffer;
+ UINT32 ToolOutputLength;
+ CHAR16 *UIName;
+ UINT32 UINameSize;
+ BOOLEAN HasDepexSection;
+ UINT32 NumberOfSections;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ CHAR8 *BlankChar;
+ UINT8 *UncompressedBuffer;
+ UINT32 UncompressedLength;
+ UINT8 *CompressedBuffer;
+ UINT32 CompressedLength;
+ UINT8 CompressionType;
+ DECOMPRESS_FUNCTION DecompressFunction;
+ GETINFO_FUNCTION GetInfoFunction;
+ UINT32 DstSize;
+ UINT32 ScratchSize;
+ UINT8 *ScratchBuffer;
+ BOOLEAN EncapDataNeedUpdata;
+ CHAR8 *TempDir;
+ CHAR8 *ToolInputFileFullName;
+ CHAR8 *ToolOutputFileFullName;
+ UINT8 LargeHeaderOffset;
+ UINT16 GuidAttr;
+ UINT16 DataOffset;
+ CHAR8 *UIFileName;
+ CHAR8 *ToolInputFileName;
+ CHAR8 *ToolOutputFileName;
+
+ DataOffset = 0;
+ GuidAttr = 0;
+ ParsedLength = 0;
+ ToolOutputLength = 0;
+ UINameSize = 0;
+ NumberOfSections = 0;
+ UncompressedLength = 0;
+ CompressedLength = 0;
+ CompressionType = 0;
+ DstSize = 0;
+ ScratchSize = 0;
+ Ptr = NULL;
+ ExtractionTool = NULL;
+ ToolInputFile = NULL;
+ ToolOutputFile = NULL;
+ SystemCommand = NULL;
+ SystemCommandFormatString = NULL;
+ ToolOutputBuffer = NULL;
+ UIName = NULL;
+ LocalEncapData = NULL;
+ LocalEncapDataTemp = NULL;
+ BlankChar = NULL;
+ UncompressedBuffer = NULL;
+ CompressedBuffer = NULL;
+ ScratchBuffer = NULL;
+ TempDir = NULL;
+ ToolInputFileFullName = NULL;
+ ToolOutputFileFullName = NULL;
+ ToolInputFileName = NULL;
+ ToolOutputFileFullName = NULL;
+ HasDepexSection = FALSE;
+ EncapDataNeedUpdata = TRUE;
+ LargeHeaderOffset = 0;
+
+
+ while (ParsedLength < BufferLength) {
+ Ptr = SectionBuffer + ParsedLength;
+
+ SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if (SectionLength == 0xffffff && Type == 0xff) {
+ ParsedLength += 4;
+ continue;
+ }
+ //
+ //If Size is 0xFFFFFF then ExtendedSize contains the size of the section.
+ //
+ if (SectionLength == 0xffffff) {
+ SectionLength = ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSize;
+ LargeHeaderOffset = sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+
+ switch (Type) {
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+
+ EncapDataNeedUpdata = TRUE;
+
+ Level ++;
+ NumberOfSections ++;
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+ CurrentFv->FfsAttuibutes[*FfsCount].IsFvStart = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FV_SECTION;
+
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ //
+ LocalEncapData->Data = NULL;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ LocalEncapData->FvId = *FvCount;
+ }
+
+ //
+ //save parent level FFS file's GUID name
+ //
+ LocalEncapDataTemp = CurrentFv->EncapData;
+ while (LocalEncapDataTemp->NextNode != NULL) {
+ if (LocalEncapDataTemp->Level == FfsLevel) {
+ while (LocalEncapDataTemp->RightNode != NULL) {
+ LocalEncapDataTemp = LocalEncapDataTemp->RightNode;
+ }
+ if (LocalEncapDataTemp != NULL && LocalEncapDataTemp->FvExtHeader == NULL) {
+ LocalEncapDataTemp->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (LocalEncapDataTemp->FvExtHeader == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ if (*FfsCount >= 1) {
+ if ((memcmp(&CurrentFv->FfsAttuibutes[*FfsCount - 1].GuidName, &(LocalEncapDataTemp->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) {
+ memcpy(LocalEncapDataTemp->UiName, CurrentFv->FfsAttuibutes[*FfsCount - 1].UiName, _MAX_PATH);
+ LocalEncapDataTemp->UiNameSize = CurrentFv->FfsAttuibutes[*FfsCount - 1].UiNameSize;
+ LocalEncapDataTemp->DepexLen = CurrentFv->FfsAttuibutes[*FfsCount - 1].DepexLen;
+ LocalEncapDataTemp->Depex = malloc (LocalEncapDataTemp->DepexLen);
+ if (LocalEncapDataTemp->Depex == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ memcpy(LocalEncapDataTemp->Depex, CurrentFv->FfsAttuibutes[*FfsCount - 1].Depex, LocalEncapDataTemp->DepexLen);
+ }
+ }
+ }
+ break;
+ }
+ LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+ }
+
+ Status = LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag, TRUE);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "printing of FV section contents failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ if (*FfsCount >= 1) {
+ CurrentFv->FfsAttuibutes[*FfsCount -1].IsFvEnd = TRUE;
+ }
+ break;
+
+ case EFI_SECTION_COMPRESSION:
+ Level ++;
+ NumberOfSections ++;
+
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ EncapDataNeedUpdata = FALSE;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_COMPRESS_SECTION;
+
+ //
+ // Store the compress type
+ //
+ LocalEncapData->Data = malloc (sizeof (UINT8));
+
+ if (LocalEncapData->Data == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ } else {
+ LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+ if (LocalEncapData->RightNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData = LocalEncapData->RightNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_COMPRESS_SECTION;
+
+ //
+ // Store the compress type
+ //
+ LocalEncapData->Data = malloc (sizeof (UINT8));
+
+ if (LocalEncapData->Data == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+
+ }
+
+ //
+ // Process compressed section
+ //
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ UncompressedBuffer = NULL;
+ CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION) - LargeHeaderOffset;
+ UncompressedLength = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+ //printf (" Compression Type: EFI_NOT_COMPRESSED\n");
+ if (CompressedLength != UncompressedLength) {
+ Error ("FMMT", 0, 0, "file is not compressed, but the compressed length does not match the uncompressed length", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ GetInfoFunction = EfiGetInfo;
+ DecompressFunction = EfiDecompress;
+
+ CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+
+ Status = GetInfoFunction (CompressedBuffer, CompressedLength, &DstSize, &ScratchSize);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error getting compression info from compression section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ if (DstSize != UncompressedLength) {
+ Error ("FMMT", 0, 0003, "compression error in the compression section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ ScratchBuffer = malloc (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UncompressedBuffer = malloc (UncompressedLength);
+ if (UncompressedBuffer == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ free (ScratchBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Decompress the section.
+ //
+ Status = DecompressFunction (
+ CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ ScratchBuffer,
+ ScratchSize
+ );
+ free (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "decompress failed", NULL);
+ free (UncompressedBuffer);
+ return EFI_SECTION_ERROR;
+ }
+ } else {
+ Error ("FMMT", 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType);
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection ( UncompressedBuffer,
+ UncompressedLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated);
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ //
+ // We need to deallocate Buffer
+ //
+ free (UncompressedBuffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "failed to parse section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ //
+ // Process GUID defined
+ // looks up the appropriate tool to use for extracting
+ // a GUID defined FV section.
+ //
+ Level ++;
+ NumberOfSections++;
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ EncapDataNeedUpdata = FALSE;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+ GuidAttr = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->Attributes;
+ DataOffset = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->DataOffset;
+
+ if ((ViewFlag) && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0)) {
+ ToolOutputBuffer = Ptr + DataOffset;
+ ToolOutputLength = SectionLength - DataOffset;
+ Status = LibParseSection(
+ ToolOutputBuffer,
+ ToolOutputLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ break;
+ }
+
+ if (EncapDataNeedUpdata) {
+
+ //
+ // Put in this is an FFS with FV section
+ //
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_GUIDED_SECTION;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ // include DataOffset + Attributes
+ //
+
+ LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4);
+
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // include guid attribute and dataoffset
+ //
+ memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4);
+
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ } else {
+ LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+ if (LocalEncapData->RightNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData = LocalEncapData->RightNode;
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_GUIDED_SECTION;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ // include DataOffset + Attributes
+ //
+
+ LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4);
+
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // include guid attribute and dataoffset
+ //
+ memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4);
+
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ }
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid
+ );
+
+ if (ExtractionTool != NULL && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0)) {
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ free (ExtractionTool);
+ return EFI_SECTION_ERROR;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ ToolInputFile = GenTempFile ();
+ if (ToolInputFile == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (ExtractionTool);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolOutputFile = GenTempFile ();
+ if (ToolOutputFile == NULL) {
+ free (ToolInputFile);
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (ExtractionTool);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolInputFileName = strrchr(ToolInputFile, OS_SEP);
+ if (ToolInputFileName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+ ToolOutputFileName = strrchr(ToolOutputFile, OS_SEP);
+ if (ToolOutputFileName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+
+ ToolInputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolInputFileName) + 1);
+ if (ToolInputFileFullName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ExtractionTool);
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolOutputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolOutputFileName) + 1);
+
+ if (ToolOutputFileFullName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolInputFileFullName);
+ free (ExtractionTool);
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName);
+ sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileName);
+
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "%s -d -o \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (ExtractionTool) +
+ strlen (ToolInputFileFullName) +
+ strlen (ToolOutputFileFullName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "%s -d -o \"%s\" \"%s\"",
+ ExtractionTool,
+ ToolOutputFileFullName,
+ ToolInputFileFullName
+ );
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+
+ Status = PutFileImage (
+ ToolInputFileFullName,
+ (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset
+ );
+
+ if (HasDepexSection) {
+ HasDepexSection = FALSE;
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "unable to decoded GUIDED section", NULL);
+ free (SystemCommand);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ remove (ToolInputFileFullName);
+ free (ToolInputFileFullName);
+ return EFI_SECTION_ERROR;
+ }
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ printf("Command failed: %s\n", SystemCommand);
+ free (SystemCommand);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ remove (ToolInputFileFullName);
+ free (ToolInputFileFullName);
+ return EFI_ABORTED;
+ }
+ free (SystemCommand);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ ToolInputFile = NULL;
+ ToolInputFileFullName = NULL;
+
+
+ Status = GetFileImage (
+ ToolOutputFileFullName,
+ (CHAR8 **)&ToolOutputBuffer,
+ &ToolOutputLength
+ );
+ remove (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ ToolOutputFile = NULL;
+ ToolOutputFileFullName = NULL;
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "unable to read decoded GUIDED section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection (
+ ToolOutputBuffer,
+ ToolOutputLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ } else if ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0){
+ Status = LibParseSection (
+ Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ }else {
+ //
+ // We don't know how to parse it now.
+ //
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ Error ("FMMT", 0, 0003, "Error parsing section", \
+ "EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in %s file.", mGuidToolDefinition);
+ printf(" Its GUID is: ");
+ PrintGuid(&(((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->SectionDefinitionGuid));
+ return EFI_UNSUPPORTED;
+ }
+ break;
+
+ //
+ //Leaf sections
+ //
+ case EFI_SECTION_RAW:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PE32:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PIC:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_TE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_COMPATIBILITY16:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_VERSION:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ break;
+ case EFI_SECTION_PEI_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+ memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+ CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+ break;
+ case EFI_SECTION_DXE_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+ memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+ CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+ break;
+ case EFI_SECTION_SMM_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+ memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+ CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+ break;
+
+ case EFI_SECTION_USER_INTERFACE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+ UiSectionLength = GetLength (((EFI_USER_INTERFACE_SECTION *) Ptr)->CommonHeader.Size);
+ if (UiSectionLength == 0xffffff) {
+ UiSectionLength = ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonHeader.ExtendedSize;
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER2);
+ } else {
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER);
+ }
+
+ UIName = (CHAR16 *) malloc (UINameSize + 2);
+ if (UIName != NULL) {
+ memset (UIName, '\0', UINameSize + 2);
+ if (UiSectionLength >= 0xffffff) {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameString, UINameSize);
+ } else {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UINameSize);
+ }
+ } else {
+ Error ("FMMT", 0, 0001, "Memory allocate error!", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlankChar = LibConstructBlankChar( CurrentFv->FvLevel * 2);
+ if (BlankChar == NULL) {
+ free(UIName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (ViewFlag) {
+ UIFileName = malloc (UINameSize + 2);
+ if (UIFileName == NULL) {
+ Error ("FMMT", 0, 4001, "Memory allocation fail!", NULL);
+ free (UIName);
+ free (BlankChar);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Unicode2AsciiString (UIName, UIFileName);
+ fprintf(stdout, "%sFile \"%s\"\n", BlankChar, UIFileName);
+ free(UIFileName);
+ }
+ free (BlankChar);
+
+ //
+ // If Ffs file has been generated, then the FfsCount should decrease 1.
+ //
+ if (*IsFfsGenerated) {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UINameSize);
+ CurrentFv->FfsAttuibutes[*FfsCount -1].UiNameSize = UINameSize;
+ } else {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UINameSize);
+ CurrentFv->FfsAttuibutes[*FfsCount].UiNameSize = UINameSize;
+ }
+
+ HasDepexSection = FALSE;
+ free(UIName);
+ UINameSize = 0;
+
+ break;
+ default:
+ break;
+ }
+
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+
+ if (ParsedLength < BufferLength) {
+ Error ("FMMT", 0, 0003, "sections do not completely fill the sectioned buffer being parsed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Iterates through the files contained within the firmware volume
+
+ @param[in] Fv - Address of the Fv in memory
+ @param[in] Key - Should be 0 to get the first file. After that, it should be
+ passed back in without modifying it's contents to retrieve
+ subsequent files.
+ @param[in] File- Output file pointer
+ File == NULL - invalid parameter
+ otherwise - *File will be update to the location of the file
+
+ @return EFI_STATUS
+ EFI_NOT_FOUND
+ EFI_VOLUME_CORRUPTED
+
+**/
+EFI_STATUS
+FvBufFindNextFile (
+ IN VOID *Fv,
+ IN OUT UINTN *Key,
+ OUT VOID **File
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FFS_FILE_HEADER *fhdr;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN fsize;
+ EFI_STATUS Status;
+ UINTN fvSize;
+
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ fhdr = NULL;
+
+ if (Fv == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FvBufGetSize (Fv, &fvSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (*Key == 0) {
+ if (hdr->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)hdr + hdr->ExtHeaderOffset);
+ *Key = (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSize;
+ *Key = (UINTN)ALIGN_POINTER(*Key, 8);
+ } else {
+ *Key = hdr->HeaderLength;
+ }
+ }
+
+ FvbAttributes = hdr->Attributes;
+
+ for(
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8);
+ (*Key + sizeof (*fhdr)) < fvSize;
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8)
+ ) {
+ fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
+ fsize = GetFfsFileLength (fhdr);
+ if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_VALID
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_INVALID
+ )
+ ) {
+ *Key = *Key + 1;
+ continue;
+ } else if(
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_MARKED_FOR_UPDATE
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DELETED
+ )
+ ) {
+ *Key = *Key + fsize;
+ continue;
+ } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DATA_VALID
+ )
+ ) {
+ *File = (UINT8*)hdr + *Key;
+ *Key = *Key + fsize;
+ return EFI_SUCCESS;
+ }
+
+ *Key = *Key + 1;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ TODO: Add function description
+
+ FvImage - TODO: add argument description
+ FileHeader - TODO: add argument description
+ ErasePolarity - TODO: add argument description
+
+ EFI_SUCCESS - TODO: Add description for return value
+ EFI_ABORTED - TODO: Add description for return value
+
+**/
+EFI_STATUS
+LibGetFileInfo (
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ BOOLEAN ErasePolarity,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ ENCAP_INFO_DATA **CurrentFvEncapData,
+ UINT32 *FfsCount,
+ UINT8 *FvCount,
+ BOOLEAN ViewFlag
+ )
+{
+ UINT32 FileLength;
+ UINT8 FileState;
+ UINT8 Checksum;
+ EFI_FFS_FILE_HEADER2 BlankHeader;
+ EFI_STATUS Status;
+ UINT8 GuidBuffer[PRINTED_GUID_BUFFER_SIZE];
+ ENCAP_INFO_DATA *LocalEncapData;
+ BOOLEAN EncapDataNeedUpdateFlag;
+ BOOLEAN IsGeneratedFfs;
+ UINT32 FfsFileHeaderSize;
+
+ Status = EFI_SUCCESS;
+
+ LocalEncapData = NULL;
+ EncapDataNeedUpdateFlag = TRUE;
+ IsGeneratedFfs = FALSE;
+
+ FfsFileHeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FileLength = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ //
+ // Check if we have free space
+ //
+ if (ErasePolarity) {
+ memset (&BlankHeader, -1, FfsFileHeaderSize);
+ } else {
+ memset (&BlankHeader, 0, FfsFileHeaderSize);
+ }
+
+ //
+ // Is this FV blank?
+ //
+ if (memcmp (&BlankHeader, CurrentFile, FfsFileHeaderSize) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Print file information.
+ //
+ FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)CurrentFile);
+ PrintGuidToBuffer (&(CurrentFile->Name), GuidBuffer, PRINTED_GUID_BUFFER_SIZE, FALSE);
+ if (FileState == EFI_FILE_DATA_VALID) {
+ //
+ // Calculate header checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize);
+ Checksum = (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum.File);
+ Checksum = (UINT8) (Checksum - CurrentFile->State);
+ if (Checksum != 0) {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum", GuidBuffer);
+ return EFI_ABORTED;
+ }
+
+ if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ //
+ // Calculate file checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFileHeaderSize), FileLength - FfsFileHeaderSize);
+ Checksum = Checksum + CurrentFile->IntegrityCheck.Checksum.File;
+ if (Checksum != 0) {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid file checksum", GuidBuffer);
+ return EFI_ABORTED;
+ }
+ } else {
+ if (CurrentFile->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum -- not set to fixed value of 0xAA", GuidBuffer);
+ return EFI_ABORTED;
+ }
+ }
+ } else {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has the invalid/unrecognized file state bits", GuidBuffer);
+ return EFI_ABORTED;
+ }
+
+ Level += 1;
+
+ if ((CurrentFile->Type != EFI_FV_FILETYPE_ALL) && (CurrentFile->Type != EFI_FV_FILETYPE_FFS_PAD)) {
+
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ EncapDataNeedUpdateFlag = FALSE;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+
+ if (EncapDataNeedUpdateFlag) {
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FFS;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // Store the header of FFS file.
+ //
+ LocalEncapData->Data = malloc (FfsFileHeaderSize);
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1;
+ LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2;
+ LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3;
+ LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0];
+ LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1];
+ LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2];
+ LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3];
+ LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4];
+ LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5];
+ LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6];
+ LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7];
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ }else{
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->RightNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->RightNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FFS;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // Store the header of FFS file.
+ //
+ LocalEncapData->Data = malloc (FfsFileHeaderSize);
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1;
+ LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2;
+ LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3;
+ LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0];
+ LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1];
+ LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2];
+ LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3];
+ LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4];
+ LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5];
+ LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6];
+ LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7];
+ LocalEncapData->RightNode = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ if ( CurrentFile->Type == EFI_FV_FILETYPE_RAW){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag){
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ } else if( CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD){
+ //EFI_FV_FILETYPE_FFS_PAD
+ } else {
+ //
+ // All other files have sections
+ //
+ Status = LibParseSection (
+ (UINT8 *) ((UINTN) CurrentFile + FfsFileHeaderSize),
+ FileLength - FfsFileHeaderSize,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ Level,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ &IsGeneratedFfs
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ printf ("ERROR: Parsing the FFS file.\n");
+ return Status;
+ }
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get firmware information. Including the FV headers,
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN ENCAP_INFO_DATA **CurrentFvEncapData,
+ IN UINT32 *FfsCount,
+ IN OUT UINT8 *FvCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfFiles;
+ BOOLEAN ErasePolarity;
+ UINTN FvSize;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ UINTN Key;
+ ENCAP_INFO_DATA *LocalEncapData;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHdrPtr;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHdr;
+
+ NumberOfFiles = 0;
+ Key = 0;
+ LocalEncapData = NULL;
+ CurrentFile = NULL;
+ FvHdr = (EFI_FIRMWARE_VOLUME_HEADER *)Fv;
+
+
+ Level += 1;
+ *FvCount += 1;
+ CurrentFv->FvLevel += 1;
+
+ Status = FvBufGetSize (Fv, &FvSize);
+
+ ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE;
+
+ Status = LibReadFvHeader (Fv, ViewFlag, CurrentFv->FvLevel, *FvCount - 1, CurrentFv->FvName);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error parsing FV image", "Header is invalid");
+ return EFI_ABORTED;
+ }
+
+ if (!IsChildFv) {
+ //
+ // Write FV header information into CurrentFv struct.
+ //
+ CurrentFv->FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvHdr->HeaderLength);
+
+ if (CurrentFv->FvHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV Header information
+ //
+ memcpy(CurrentFv->FvHeader, Fv, FvHdr->HeaderLength);
+ CurrentFv->FvExtHeader = NULL;
+ CurrentFv->FvUiName = NULL;
+
+ //
+ // Exist Extend FV header.
+ //
+ if (CurrentFv->FvHeader->ExtHeaderOffset != 0){
+ ExtHdrPtr = (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset);
+ CurrentFv->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+ if (CurrentFv->FvExtHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy (CurrentFv->FvExtHeader, (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ LibExtractFvUiName(CurrentFv->FvExtHeader, &CurrentFv->FvUiName);
+ }
+ }
+
+ //
+ // Put encapsulate information into structure.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData == NULL && !IsChildFv) {
+ //
+ // First time in, the root FV
+ //
+ LocalEncapData = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+ CurrentFv->EncapData = LocalEncapData;
+ if (CurrentFv->EncapData == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ CurrentFv->EncapData->FvExtHeader = NULL;
+ CurrentFv->EncapData->Depex = NULL;
+ CurrentFv->EncapData->DepexLen = 0;
+ CurrentFv->EncapData->UiNameSize = 0;
+ CurrentFv->EncapData->Level = Level;
+ CurrentFv->EncapData->Type = FMMT_ENCAP_TREE_FV;
+ CurrentFv->EncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ CurrentFv->EncapData->FvId = *FvCount;
+
+ if (CurrentFv->EncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset);
+ CurrentFv->EncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+ if (CurrentFv->EncapData->FvExtHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(CurrentFv->EncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ }
+
+ CurrentFv->EncapData->NextNode = NULL;
+ CurrentFv->EncapData->RightNode = NULL;
+ } else if (LocalEncapData == NULL) {
+ return EFI_ABORTED;
+ } else if (IsChildFv) {
+
+ LocalEncapData = *CurrentFvEncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FV;
+ LocalEncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ LocalEncapData->FvId = *FvCount;
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(ExtHdrPtr->ExtHeaderSize);
+
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(LocalEncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ }
+
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+
+ }
+
+
+ //
+ // Get the first file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the first file in the FV image");
+ return Status;
+ }
+
+ while (CurrentFile != NULL) {
+
+ //
+ // Increment the number of files counter
+ //
+ NumberOfFiles++;
+
+ //
+ // Store FFS file Header information
+ //
+ CurrentFv->FfsHeader[*FfsCount].Attributes = CurrentFile->Attributes;
+ CurrentFv->FfsHeader[*FfsCount].IntegrityCheck = CurrentFile->IntegrityCheck;
+ CurrentFv->FfsHeader[*FfsCount].Name = CurrentFile->Name;
+ CurrentFv->FfsHeader[*FfsCount].Size[0] = CurrentFile->Size[0];
+ CurrentFv->FfsHeader[*FfsCount].Size[1] = CurrentFile->Size[1];
+ CurrentFv->FfsHeader[*FfsCount].Size[2] = CurrentFile->Size[2];
+ CurrentFv->FfsHeader[*FfsCount].State = CurrentFile->State;
+ CurrentFv->FfsHeader[*FfsCount].Type = CurrentFile->Type;
+ CurrentFv->FfsHeader[*FfsCount].ExtendedSize = CurrentFile->ExtendedSize;
+ CurrentFv->FfsAttuibutes[*FfsCount].Offset = Key - GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ CurrentFv->FfsAttuibutes[*FfsCount].FvLevel = CurrentFv->FvLevel;
+ if (CurrentFv->FvLevel > CurrentFv->MulFvLevel) {
+ CurrentFv->MulFvLevel = CurrentFv->FvLevel;
+ }
+ //
+ // Display info about this file
+ //
+ Status = LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error parsing FV image", "failed to parse a file in the FV");
+ return Status;
+ }
+
+ //
+ // Get the next file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the next file in the FV image");
+ return Status;
+ }
+ }
+
+ if (IsChildFv) {
+ if (CurrentFv->FvLevel > 1) {
+ CurrentFv->FvLevel -= 1;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ )
+{
+ UINT32 OccupiedSize;
+
+ OccupiedSize = ActualSize;
+ while ((OccupiedSize & (Alignment - 1)) != 0) {
+ OccupiedSize++;
+ }
+
+ return OccupiedSize;
+}
+
+
+
+EFI_STATUS
+LibDeleteAndRenameFfs(
+ IN CHAR8* DeleteFile,
+ IN CHAR8* NewFile
+)
+{
+ CHAR8* SystemCommand;
+ CHAR8* TemDir;
+ SystemCommand = NULL;
+
+ if (DeleteFile == NULL ||
+ NewFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete the file of the specified extract FFS file.
+ //
+ SystemCommand = malloc (
+ strlen (DEL_STR) +
+ strlen (DeleteFile) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ DEL_STR,
+ DeleteFile
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ //
+ // Create a copy the new file.
+ //
+
+ SystemCommand = malloc (
+ strlen (COPY_STR) +
+ strlen (NewFile) +
+ strlen (DeleteFile) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ COPY_STR,
+ NewFile,
+ DeleteFile
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Converts ASCII characters to Unicode.
+ Assumes that the Unicode characters are only these defined in the ASCII set.
+
+ String - Pointer to string that is written to FILE.
+ UniString - Pointer to unicode string
+
+ The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+ IN CHAR8 *String,
+ OUT CHAR16 *UniString
+ )
+{
+ while (*String != '\0') {
+ *(UniString++) = (CHAR16) *(String++);
+ }
+ //
+ // End the UniString with a NULL.
+ //
+ *UniString = '\0';
+}
+
+
+EFI_STATUS
+LibCreateGuidedSectionOriginalData(
+ IN CHAR8* FileIn,
+ IN CHAR8* ToolName,
+ IN CHAR8* FileOut
+)
+{
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+
+ if (FileIn == NULL ||
+ ToolName == NULL ||
+ FileOut == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete the file of the specified extract FFS file.
+ //
+ SystemCommandFormatString = "%s -e \"%s\" -o \"%s\"";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (FileIn) +
+ strlen (ToolName) +
+ strlen (FileOut) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ "%s -e \"%s\" -o \"%s\"",
+ ToolName,
+ FileIn,
+ FileOut
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ printf("Command failed: %s\n", SystemCommand);
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function convert the FV header's attribute to a string. The converted string
+ will be put into an INF file as the input of GenFV.
+
+ @param[in] Attr FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+ @retval EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+LibFvHeaderAttributeToStr (
+ IN EFI_FVB_ATTRIBUTES_2 Attr,
+ IN FILE* InfFile
+)
+{
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ LocalStr = (CHAR8 *) malloc (1024 * 4);
+
+ if (LocalStr == NULL) {
+ printf ("Memory allocate error!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', 1024 * 4);
+
+ if (Attr == 0 || InfFile == NULL) {
+ free (LocalStr);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ strncat (LocalStr, "[attributes] \n", sizeof("[attributes] \n"));
+
+ if (Attr & EFI_FVB2_READ_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_DISABLED_CAP = TRUE \n", sizeof ("EFI_READ_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_ENABLED_CAP = TRUE \n", sizeof ("EFI_READ_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_STATUS) {
+ strncat (LocalStr, "EFI_READ_STATUS = TRUE \n", sizeof ("EFI_READ_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_DISABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_ENABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_STATUS = TRUE \n", sizeof ("EFI_WRITE_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_CAP) {
+ strncat (LocalStr, "EFI_LOCK_CAP = TRUE \n", sizeof ("EFI_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_LOCK_STATUS = TRUE \n", sizeof ("EFI_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_STICKY_WRITE) {
+ strncat (LocalStr, "EFI_STICKY_WRITE = TRUE \n", sizeof ("EFI_STICKY_WRITE = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_MEMORY_MAPPED) {
+ strncat (LocalStr, "EFI_MEMORY_MAPPED = TRUE \n", sizeof ("EFI_MEMORY_MAPPED = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_ERASE_POLARITY) {
+ strncat (LocalStr, "EFI_ERASE_POLARITY = 1 \n", sizeof ("EFI_ERASE_POLARITY = 1 \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_CAP) {
+ strncat (LocalStr, "EFI_READ_LOCK_CAP = TRUE \n", sizeof ("EFI_READ_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_CAP) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_CAP = TRUE \n", sizeof ("EFI_WRITE_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_STATUS = TRUE \n", sizeof ("EFI_WRITE_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ //
+ // Alignment
+ //
+ if (Attr & EFI_FVB2_ALIGNMENT_1) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1G = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2G = TRUE \n"));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while writing data to %p file.", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] BlockMap FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibFvHeaderOptionToStr (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
+ IN FILE* InfFile,
+ IN BOOLEAN IsRootFv
+)
+{
+ CHAR8 *LocalStr;
+ CHAR8 *TempStr;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+
+ LocalStr = NULL;
+ TempStr = NULL;
+
+ if (FvHeader == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // This section will not over 1024 bytes and each line will never over 128 bytes.
+ //
+ LocalStr = (CHAR8 *) malloc (1024);
+ TempStr = (CHAR8 *) malloc (128);
+
+ if (LocalStr == NULL ||
+ TempStr == NULL ) {
+ if (LocalStr != NULL) {
+ free (LocalStr);
+ }
+ if (TempStr != NULL) {
+ free (TempStr);
+ }
+ printf ("Memory allocate error! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlockMap = FvHeader->BlockMap;
+ memset (LocalStr, '\0', 1024);
+ memset (TempStr, '\0', 128);
+
+ strncat (LocalStr, "[options] \n", sizeof("[Options] \n"));
+
+
+ snprintf (TempStr, 128, "EFI_BLOCK_SIZE = 0x%x \n", BlockMap->Length);
+ strncat (LocalStr, TempStr, strlen(TempStr));
+
+ if (IsRootFv) {
+ snprintf (TempStr, 128, "EFI_NUM_BLOCKS = 0x%x \n", BlockMap->NumBlocks);
+ strncat (LocalStr, TempStr, strlen(TempStr));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while writing data to %p file.", (void*)InfFile);
+ free (LocalStr);
+ free (TempStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+ free (TempStr);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] FfsName Ffs file path/name.
+ @param[out] InfFile InfFile contain FV header attribute information
+ @param[in] FirstIn Is the first time call this function? If yes, should create [files] section.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibAddFfsFileToFvInf (
+ IN CHAR8 *FfsName,
+ IN FILE* InfFile,
+ IN BOOLEAN FirstIn
+)
+{
+
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ if (FfsName == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (strlen(FfsName) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ LocalStr = (CHAR8 *) malloc (_MAX_PATH);
+
+ if (LocalStr == NULL) {
+ printf ("Memory allocate error! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', _MAX_PATH);
+
+ if (FirstIn) {
+ sprintf (LocalStr, "[files] \nEFI_FILE_NAME = %s \n", FfsName);
+ } else {
+ sprintf (LocalStr, "EFI_FILE_NAME = %s \n", FfsName);
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while writing data to %p file.", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Convert EFI file to PE or TE section
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] Type PE or TE and UI/Version
+ @param[in] OutputFilePath .te or .pe file
+ @param[in] UiString String for generate UI section usage, this parameter is optional
+ unless Type is EFI_SECTION_USER_INTERFACE.
+ @param[in] VerString String for generate Version section usage, this parameter is optional
+ unless Type is EFI_SECTION_VERSION.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibCreateFfsSection (
+ IN FV_INFORMATION *FvInFd, OPTIONAL
+ IN CHAR8* InputFilePath, OPTIONAL
+ IN CHAR8* Sections, OPTIONAL
+ IN UINT8 Type,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* UiString, OPTIONAL
+ IN CHAR8* VerString, OPTIONAL
+ IN CHAR8* GuidToolGuid, OPTIONAL
+ IN UINT16 GuidHeaderLength,
+ IN UINT16 GuidAttr,
+ IN CHAR8* CompressType OPTIONAL
+ )
+{
+ //EFI_STATUS Status;
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ FILE *file;
+ UINT8 Buffer[4];
+ int BitNum;
+ int Position;
+ UINT32 AlignmentValue;
+ //
+ // Workaround for static code checkers.
+ // Ensures the size of 'AlignmentStr' can hold all the digits of an
+ // unsigned 32-bit integer plus the size unit character.
+ //
+ char AlignmentStr[16];
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ strcpy(AlignmentStr,"1");
+ //
+ // Call GenSec tool to generate FFS section.
+ //
+
+ //
+ // -s SectionType.
+ //
+ if (Type != 0) {
+ switch (Type) {
+ //
+ // Process compression section
+ //
+ case EFI_SECTION_COMPRESSION:
+ SystemCommandFormatString = "GenSec -s %s -c %s \"%s\" -o \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (CompressType) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec -s %s -c %s \"%s\" -o \"%s\"",
+ mSectionTypeName[Type],
+ CompressType,
+ InputFilePath,
+ OutputFilePath
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ //
+ // Process GUID defined section
+ //
+ case EFI_SECTION_GUID_DEFINED:
+ SystemCommandFormatString = "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (GuidToolGuid) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ strlen (mGuidSectionAttr[GuidAttr&0x01]) +
+ strlen (mGuidSectionAttr[GuidAttr&0x02]) +
+ 4 +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d",
+ mSectionTypeName[Type],
+ GuidToolGuid,
+ InputFilePath,
+ OutputFilePath,
+ mGuidSectionAttr[GuidAttr&0x01],
+ mGuidSectionAttr[GuidAttr&0x02],
+ GuidHeaderLength
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+
+ SystemCommandFormatString = "GenSec -s %s \"%s\" -o \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec -s %s \"%s\" -o \"%s\"",
+ mSectionTypeName[Type],
+ InputFilePath,
+ OutputFilePath
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ default:
+ Error ("FMMT", 0, 0003, "Please specify the section type while call GenSec tool.", NULL);
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ //
+ // Create Dummy section.
+ //
+ file = fopen(InputFilePath, "rb");
+ if (file == NULL) {
+ Error(NULL, 0, 0001, "Error opening the file", InputFilePath);
+ return EFI_INVALID_PARAMETER;
+ }
+ // The Section Struct, 3 bits for Size, then 1 bit for Type
+ if (fread(Buffer, 1, (size_t)(4), file) != (size_t)(4)) {
+ fclose(file);
+ return EFI_ABORTED;
+ }
+ if (*(Buffer + 3) == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
+ // The Section Struct, if size is not 0xFFFF, the length is 4
+ Position = 4;
+ // If Size is 0xFFFFFF then ExtendedSize contains the size of the section
+ if ((*Buffer == 0xFF) && (*(Buffer + 1) == 0xFF) && (*(Buffer + 2) == 0xFF)) {
+ Position = 8;
+ }
+ //Per EFI_FIRMWARE_VOLUME_HEADER struct, 0x2E bit is EFI_FVB_ATTRIBUTES_2 attr
+ fseek(file, 0x2E + Position, SEEK_SET);
+ BitNum = fgetc(file);
+ AlignmentValue = 1 << (BitNum & 0x1F);
+ if (AlignmentValue >= 0x400){
+ if (AlignmentValue >= 0x10000){
+ strcpy(AlignmentStr,"64K");
+ }
+ else{
+ sprintf(AlignmentStr, "%d", AlignmentValue/0x400);
+ strcat(AlignmentStr, "K");
+ }
+ }
+ else{
+ sprintf(AlignmentStr, "%d", AlignmentValue);
+ }
+ strcpy(FvInFd->AlignmentStr, AlignmentStr);
+ }
+ fclose(file);
+ SystemCommandFormatString = "GenSec \"%s\" -o \"%s\" --sectionalign %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 4 + // Alignment maximum length
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec \"%s\" -o \"%s\" --sectionalign %s",
+ InputFilePath,
+ OutputFilePath,
+ AlignmentStr
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Encapsulate FFSs to FV
+
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] BlockSize BlockSize is one HEX or DEC format value required by FV image.
+ @param[in] FileTakeSize
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapsulateFfsToFv (
+ IN CHAR8* InfFilePath,
+ IN CHAR8* InputFFSs,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* FvGuidName,
+ IN BOOLEAN IsLargeFile
+ )
+{
+
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ CHAR8* FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3";
+
+ if (IsLargeFile == TRUE) {
+ FfsGuid = "5473c07a-3dcb-4dca-bd6f-1e9689e7349a";
+ }
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+
+ if (OutputFilePath == NULL ||
+ InfFilePath == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InfFilePath != NULL) {
+ if (FvGuidName == NULL) {
+ SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\"";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (InfFilePath) +
+ strlen (FfsGuid) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFv -i \"%s\" -g %s -o \"%s\"",
+ InfFilePath, // -i
+ FfsGuid, // -g
+ OutputFilePath // -o
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+
+ free(SystemCommand);
+ } else {
+ //
+ // Have FvGuidName in it.
+ //
+ SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (InfFilePath) +
+ strlen (FfsGuid) +
+ strlen (OutputFilePath) +
+ strlen (FvGuidName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s",
+ InfFilePath, // -i
+ FfsGuid, // -g
+ OutputFilePath, // -o
+ FvGuidName // FvNameGuid
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Convert a GUID to a string.
+
+
+ @param[in] Guid - Pointer to GUID to print.
+
+
+ @return The string after convert.
+
+**/
+CHAR8 *
+LibFmmtGuidToStr (
+ IN EFI_GUID *Guid
+)
+{
+ CHAR8 * Buffer;
+
+ Buffer = NULL;
+
+ if (Guid == NULL) {
+ printf ("The guid is NULL while convert guid to string! \n");
+ return NULL;
+ }
+
+ Buffer = (CHAR8 *) malloc (36 + 1);
+
+ if (Buffer == NULL) {
+ printf ("Error while allocate resource! \n");
+ return NULL;
+ }
+ memset (Buffer, '\0', 36 + 1);
+
+ sprintf (
+ Buffer,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ Guid->Data1,
+ Guid->Data2,
+ Guid->Data3,
+ Guid->Data4[0],
+ Guid->Data4[1],
+ Guid->Data4[2],
+ Guid->Data4[3],
+ Guid->Data4[4],
+ Guid->Data4[5],
+ Guid->Data4[6],
+ Guid->Data4[7]
+ );
+
+ return Buffer;
+}
+
+
+/**
+ Encapsulate an FFS section file to an FFS file.
+
+ @param[in] Type Type is one FV file type defined in PI spec, which is one type of EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,
+ EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,
+ EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION, EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE. This option is required.
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] FileGuid FileGuid is the unique identifier for this FFS file. This option is required.
+ @param[in] Fixed Set fixed attribute in FFS file header to indicate that the file may not be moved from its present location.
+ @param[in] SectionAlign FileAlign specifies FFS file alignment, which only support the following alignment: 8,16,128,512,1K,4K,32K,64K.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapSectionFileToFFS (
+ IN UINT8 Type,
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath,
+ IN EFI_GUID FileGuid,
+ IN BOOLEAN Fixed,
+ IN CHAR8* SectionAlign
+ )
+{
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ CHAR8* GuidStr;
+
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ GuidStr = NULL;
+
+ GuidStr = LibFmmtGuidToStr(&FileGuid);
+
+ if (GuidStr == NULL) {
+ return EFI_ABORTED;
+ }
+
+
+ //
+ // -t Type
+ // -i InputFilePath
+ // -o OutPutFilePath
+ // -g FileGuid
+ // -x Fixed
+ // -n SectionAlign
+ //
+
+ if (Fixed) {
+ SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 4 +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s",
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath, // -o
+ SectionAlign
+ );
+
+ free (GuidStr);
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ } else {
+ SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 4 +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (GuidStr);
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s",
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath, // -o
+ SectionAlign
+ );
+
+ free (GuidStr);
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibCreateNewFdCopy(
+ IN CHAR8* OldFd,
+ IN CHAR8* NewFd
+)
+{
+
+ FILE* NewFdFile;
+ FILE* OldFdFile;
+ CHAR8 *NewFdDir;
+ CHAR8 *OldFdDir;
+ UINT64 FdLength;
+ UINT32 Count;
+ BOOLEAN UseNewDirFlag;
+ CHAR8 *Buffer;
+
+ NewFdFile = NULL;
+ OldFdFile = NULL;
+ NewFdDir = NULL;
+ OldFdDir = NULL;
+ Count = 0;
+ UseNewDirFlag = FALSE;
+
+ if (OldFd == NULL ||
+ NewFd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ NewFdDir = getcwd (NULL, _MAX_PATH);
+
+ Count = strlen(NewFdDir);
+
+ if (strlen(NewFd) > Count) {
+
+ do {
+ if (NewFdDir[Count-1] == NewFd[Count-1]) {
+ Count--;
+ } else {
+ if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) {
+ return EFI_ABORTED;
+ }
+ strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1);
+ strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1);
+ UseNewDirFlag = TRUE;
+ break;
+ }
+
+ } while (Count != 1);
+
+ }else {
+ if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) {
+ return EFI_ABORTED;
+ }
+ strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1);
+ strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1);
+ UseNewDirFlag = TRUE;
+ }
+
+ if (UseNewDirFlag) {
+ NewFdFile = fopen (NewFdDir, "wb+");
+ if (NewFdFile == NULL) {
+ NewFdFile = fopen (NewFd, "wb+");
+ }
+ } else {
+ NewFdFile = fopen (NewFd, "wb+");
+ }
+ // support network path file
+ if (OldFd[0] == '\\' && OldFd[1] == '\\') {
+ OldFdFile = fopen (OldFd, "rb");
+ } else {
+ UseNewDirFlag = FALSE;
+
+ OldFdDir = getcwd (NULL, _MAX_PATH);
+
+ Count = strlen(OldFdDir);
+
+ if (strlen(OldFd) > Count) {
+
+ do {
+ if (OldFdDir[Count-1] == OldFd[Count-1]) {
+ Count--;
+ } else {
+ if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) {
+ if (NewFdFile != NULL) {
+ fclose(NewFdFile);
+ }
+ return EFI_ABORTED;
+ }
+ strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1);
+ strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1);
+ UseNewDirFlag = TRUE;
+ break;
+ }
+
+ } while (Count != 1);
+
+ }else {
+ if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) {
+ if (NewFdFile != NULL) {
+ fclose(NewFdFile);
+ }
+ return EFI_ABORTED;
+ }
+ strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1);
+ strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1);
+ UseNewDirFlag = TRUE;
+ }
+
+ if (UseNewDirFlag) {
+ OldFdFile = fopen (OldFdDir, "rb+");
+ if (OldFdFile == NULL) {
+ OldFdFile = fopen (OldFd, "rb+");
+ }
+ } else {
+ OldFdFile = fopen (OldFd, "rb+");
+ }
+ }
+
+ if (NewFdFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file.");
+ if (OldFdFile != NULL) {
+ fclose (OldFdFile);
+ }
+ return EFI_ABORTED;
+ }
+
+ if (OldFdFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file.");
+ if (NewFdFile != NULL) {
+ fclose (NewFdFile);
+ }
+ return EFI_ABORTED;
+ }
+
+
+ fseek(OldFdFile,0,SEEK_SET);
+ fseek(OldFdFile,0,SEEK_END);
+
+ FdLength = ftell(OldFdFile);
+
+ fseek(OldFdFile,0,SEEK_SET);
+ fseek(NewFdFile,0,SEEK_SET);
+
+ Buffer = malloc ((size_t)FdLength);
+
+ if (Buffer == NULL) {
+ fclose(OldFdFile);
+ fclose(NewFdFile);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) FdLength, OldFdFile) != (size_t) FdLength) {
+ Error ("FMMT", 0, 0003, "error reading FD file %s", OldFd);
+ free (Buffer);
+ fclose(OldFdFile);
+ fclose(NewFdFile);
+ return EFI_ABORTED;
+ }
+
+ if (fwrite (Buffer, 1, (size_t) FdLength, NewFdFile) != (size_t) FdLength) {
+ Error ("FMMT", 0, 0004, "error writing FD file", "cannot Create a new FD file.");
+ free (Buffer);
+ fclose(OldFdFile);
+ fclose(NewFdFile);
+ return EFI_ABORTED;
+ }
+ free (Buffer);
+ fclose(OldFdFile);
+ fclose (NewFdFile);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will assemble the filename, directory and extend and return the combined string.
+ Like FileName = file1, Dir = c:\temp extend = txt, the output string will be:
+ c:\temp\file1.txt.
+
+ @param[in]
+ @param[in]
+ @param[in]
+
+ @retrun A string contain all the input information.
+
+**/
+CHAR8 *
+LibFilenameStrExtended (
+ IN CHAR8 *FileName,
+ IN CHAR8 *Dir,
+ IN CHAR8 *Extend
+)
+{
+ CHAR8 *RetStr;
+
+ RetStr = NULL;
+
+ if (FileName == NULL) {
+ return NULL;
+ }
+
+ if (Dir == NULL || Extend == NULL) {
+ return FileName;
+ }
+
+ RetStr = (CHAR8 *) malloc (strlen (FileName) +
+ strlen (Dir) +
+ strlen (Extend) +
+ strlen ("%s%s.%s") +
+ 1);
+ if (RetStr == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return NULL;
+ }
+
+ memset (RetStr, '\0', (strlen (FileName) + strlen (Dir) + strlen (Extend) + strlen ("%s%s.%s") + 1));
+
+ sprintf (RetStr, "%s%s.%s", Dir, FileName, Extend);
+
+ return RetStr;
+}
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+
+ if (DirName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (access (DirName, 0) == -1){
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Delete a directory and files in it.
+ //
+
+ SystemCommand = malloc (
+ strlen (RMDIR_STR) +
+ strlen (DirName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ RMDIR_STR,
+ DirName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibGenExtFile(
+CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtPtr,
+FILE *InfFile
+)
+{
+ CHAR8 *TempDir;
+ FILE *ExtFile;
+ CHAR8 OutputExtFile[_MAX_PATH];
+ CHAR8 Line[512];
+ size_t Len;
+
+ TempDir = NULL;
+
+ TempDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) -1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) -1);
+
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ sprintf(
+ Line,
+ "%c%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X%d.ext",
+ OS_SEP,
+ (unsigned)ExtPtr->FvName.Data1,
+ ExtPtr->FvName.Data2,
+ ExtPtr->FvName.Data3,
+ ExtPtr->FvName.Data4[0],
+ ExtPtr->FvName.Data4[1],
+ ExtPtr->FvName.Data4[2],
+ ExtPtr->FvName.Data4[3],
+ ExtPtr->FvName.Data4[4],
+ ExtPtr->FvName.Data4[5],
+ ExtPtr->FvName.Data4[6],
+ ExtPtr->FvName.Data4[7],
+ ExtPtr->ExtHeaderSize
+ );
+ if (strlen (TempDir) + strlen (Line) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncpy (OutputExtFile, TempDir, _MAX_PATH - 1);
+ OutputExtFile[_MAX_PATH - 1] = 0;
+ strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1);
+
+
+ ExtFile = fopen(OutputExtFile, "wb+");
+ if (ExtFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) != ExtPtr->ExtHeaderSize) {
+ fclose(ExtFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(ExtFile);
+
+ strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME = ");
+ if (strlen (Line) + strlen (OutputExtFile) + 1 > sizeof(Line) / sizeof (CHAR8) - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (Line, OutputExtFile, sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ Len = strlen(Line);
+ if (fwrite(Line, 1, Len, InfFile) != Len) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a file.
+
+ @param[in] FileName Name of the file need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibFmmtDeleteFile(
+ IN CHAR8 *FileName
+)
+{
+ CHAR8* SystemCommand;
+ CHAR8 *TemDir;
+
+ SystemCommand = NULL;
+ TemDir = NULL;
+
+
+ if (FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // if the FileName is not in TemDir, we don't need to delete.
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (*(TemDir + strlen(TemDir) - 1) == OS_SEP) {
+ *(TemDir + strlen(TemDir) - 1) = '\0';
+ }
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error (NULL, 0, 2000, "Path: The current path is too long.", NULL);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ if (strstr(FileName, TemDir) == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Delete a file
+ //
+
+ SystemCommand = malloc (
+ strlen (DEL_STR) +
+ strlen (FileName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ DEL_STR,
+ FileName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibFmmtFreeFd (
+ FIRMWARE_DEVICE *Fd
+ )
+{
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *TempFv;
+ ENCAP_INFO_DATA *EncapData1;
+ ENCAP_INFO_DATA *EncapData2;
+
+ CurrentFv = NULL;
+ TempFv = NULL;
+ EncapData1 = NULL;
+ EncapData2 = NULL;
+
+ if (Fd == NULL) {
+ return;
+ }
+
+ CurrentFv = Fd->Fv;
+
+ do {
+ TempFv = CurrentFv;
+ CurrentFv = CurrentFv->FvNext;
+
+ free (TempFv->FvHeader);
+
+ if (TempFv->FvExtHeader != NULL) {
+ free (TempFv->FvExtHeader);
+ }
+ if (TempFv->FvUiName) {
+ free(TempFv->FvUiName);
+ }
+
+ //
+ // Free encapsulate data;
+ //
+ EncapData1 = TempFv->EncapData;
+
+ while (EncapData1 != NULL) {
+
+ EncapData2 = EncapData1;
+ EncapData1 = EncapData1->NextNode;
+
+ if (EncapData2->Data != NULL) {
+ free (EncapData2->Data);
+ }
+ if (EncapData2->FvExtHeader != NULL) {
+ free(EncapData2->FvExtHeader);
+ }
+ free (EncapData2);
+ EncapData2 = NULL;
+ }
+
+ EncapData1 = NULL;
+
+ free (TempFv);
+ TempFv = NULL;
+
+ } while (CurrentFv != NULL);
+
+ CurrentFv = NULL;
+ free (Fd);
+ Fd = NULL;
+
+ return;
+}
+
+/**
+ Generate the compressed section with specific type.
+ Type could be EFI_STANDARD_COMPRESSION or EFI_NOT_COMPRESSED
+
+ @param[in] InputFileName File name of the raw data.
+ @param[in] OutPutFileName File name of the sectioned data.
+ @param[in] CompressionType The compression type.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_ABORTED
+ @return EFI_OUT_OF_RESOURCES
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibGenCompressedSection (
+ CHAR8 *InputFileName,
+ CHAR8 *OutPutFileName,
+ UINT8 CompressionType
+)
+{
+ //FILE *UnCompressFile;
+ //FILE *CompressedFile;
+ //VOID *UnCompressedBuffer;
+ //VOID *CompressedBuffer;
+ //UINT32 UnCompressedSize;
+ //UINT32 CompressedSize;
+ //CHAR8 *TempName;
+ //CHAR8 *TemDir;
+ //EFI_STATUS Status;
+
+ //UnCompressFile = NULL;
+ //CompressedFile = NULL;
+ //UnCompressedBuffer = NULL;
+ //CompressedBuffer = NULL;
+ //TempName = NULL;
+ //TemDir = NULL;
+ //UnCompressedSize = 0;
+ //CompressedSize = 0;
+
+ if ( InputFileName == NULL ||
+ OutPutFileName == NULL) {
+ printf ("Error while generate compressed section!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ /*
+
+ UnCompressFile = fopen (InputFileName, "rb");
+ if (UnCompressFile == NULL) {
+ printf ("Error while open file %s \n", InputFileName);
+ return EFI_ABORTED;
+ }
+
+ TemDir = _getcwd (NULL, _MAX_PATH);
+ sprintf(TemDir, "%s\\%s", TemDir, TEMP_DIR_NAME);
+
+ TempName= LibFilenameStrExtended (strrchr(CloneString (tmpnam (NULL)),'\\'), TemDir, "comp");
+
+ CompressedFile = fopen (TempName, "wb+");
+ if (CompressedFile == NULL) {
+ printf ("Error while open file %s \n", TempName);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the original file size;
+ //
+ fseek(UnCompressFile,0,SEEK_SET);
+ fseek(UnCompressFile,0,SEEK_END);
+
+ UnCompressedSize = ftell(UnCompressFile);
+
+ fseek(UnCompressFile,0,SEEK_SET);
+
+ UnCompressedBuffer = malloc (UnCompressedSize);
+
+ if (UnCompressedBuffer == NULL) {
+ printf("Error while allocate memory! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CompressedBuffer = malloc (UnCompressedSize);
+
+ if (CompressedBuffer == NULL) {
+ printf("Error while allocate memory! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (UnCompressedBuffer, 1, (size_t) UnCompressedSize, UnCompressFile) == (size_t) UnCompressedSize) {
+ CompressedSize = UnCompressedSize;
+
+ Status = EfiCompress ( UnCompressedBuffer,
+ UnCompressedSize,
+ CompressedBuffer,
+ &CompressedSize);
+
+ if (EFI_ERROR(Status)) {
+ printf("Error while do compress operation! \n");
+ return EFI_ABORTED;
+ }
+
+ if (CompressedSize > UnCompressedSize) {
+ printf("Error while do compress operation! \n");
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error while reading file %s! \n", InputFileName);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Write the compressed data into output file
+ //
+ if (fwrite (CompressedBuffer, 1, (size_t) CompressedSize, CompressedFile) != (size_t) CompressedSize) {
+ Error ("FMMT", 0, 0004, "error writing %s file", OutPutFileName);
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ */
+
+ //
+ // Call GenSec tool to generate the compressed section.
+ //
+ LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_STD");
+
+ } else if (CompressionType == EFI_NOT_COMPRESSED) {
+
+ LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_NONE");
+
+ } else {
+ printf ("Error while generate compressed section, unknown compression type! \n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ IN ENCAP_INFO_DATA *CurrentEncapData,
+ IN UINT32 Level_Break,
+ OUT FFS_INFORMATION **OutputFile
+)
+{
+ EFI_STATUS Status;
+ UINT32 ParentType;
+ UINT8 ParentLevel;
+ UINT32 Type;
+ UINT8 Level;
+ CHAR8 *InfFileName;
+ FILE *InfFile;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ ENCAP_INFO_DATA *LocalEncapDataNext;
+ BOOLEAN FfsFoundFlag;
+ UINT32 Index;
+ UINT32 OuterIndex;
+ CHAR8 *ExtractionTool;
+ BOOLEAN IsLastLevelFfs;
+ BOOLEAN IsLeafFlagIgnore;
+ BOOLEAN FirstInFlag;
+ BOOLEAN OutputFileNameListFlag;
+ CHAR8 *InputFileName;
+ CHAR8 *OutputFileName;
+ FFS_INFORMATION *OutputFileNameList;
+ FFS_INFORMATION *ChildFileNameList;
+ FFS_INFORMATION *NewFileNameList;
+ CHAR8 *FvGuidName;
+ UINT16 GuidAttributes;
+ UINT16 GuidDataOffset;
+ BOOLEAN IsRootFv;
+ BOOLEAN IsLargeFile;
+ UINT32 EncapFvStart;
+ UINT32 EncapFvIndex;
+ CHAR8 *TmpFileName;
+ FILE *TmpFile;
+ FILE *InputFile;
+ FILE *OutFile;
+ UINT32 InputFileSize;
+ UINT32 OutputFileSize;
+ UINT32 LargeFileSize;
+ UINT8 *Buffer = NULL;
+ UINT8 SectionHeader[4] = { 0x00, 0x00, 0x00, 0x00 };
+ UINT32 Id;
+ UINT32 SubFvId;
+ UINT32 header;
+ UINT8 AlignN;
+ UINT8 AlignV[1] = {0xFF};
+ AlignN = 0;
+ Id = 0;
+ InputFileSize = 0;
+ EncapFvIndex = 0;
+ Index = 0;
+ OuterIndex = 0;
+ ParentType = 0;
+ ParentLevel = 0;
+ Type = 0;
+ Level = 0;
+ SubFvId = 0;
+ FfsFoundFlag = FALSE;
+ LocalEncapDataTemp = NULL;
+ LocalEncapDataNext = NULL;
+ ExtractionTool = NULL;
+ InputFileName = NULL;
+ OutputFileName = NULL;
+ IsLastLevelFfs = TRUE;
+ IsLeafFlagIgnore = FALSE;
+ FirstInFlag = TRUE;
+ FvGuidName = NULL;
+ OutputFileNameListFlag = TRUE;
+ IsLargeFile = FALSE;
+ OutputFileSize = 0;
+ LargeFileSize = 0x1000000;
+
+
+ OutputFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION));
+ if (OutputFileNameList == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ OutputFileNameList->FFSName = NULL;
+ OutputFileNameList->InFvId = 0;
+ OutputFileNameList->IsFFS = FALSE;
+ OutputFileNameList->ParentLevel = 0;
+ OutputFileNameList->Next = NULL;
+ OutputFileNameList->UiNameSize = 0;
+ OutputFileNameList->Depex = NULL;
+ OutputFileNameList->DepexLen = 0;
+ OutputFileNameList->FfsFoundFlag = FALSE;
+
+ ChildFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION));
+ if (ChildFileNameList == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ChildFileNameList->FFSName = NULL;
+ ChildFileNameList->InFvId = 0;
+ ChildFileNameList->ParentLevel = 0;
+ ChildFileNameList->Next = NULL;
+ ChildFileNameList->IsFFS = FALSE;
+ ChildFileNameList->UiNameSize = 0;
+ ChildFileNameList->Depex = NULL;
+ ChildFileNameList->DepexLen = 0;
+ ChildFileNameList->FfsFoundFlag = FALSE;
+ //
+ // Encapsulate from the lowest FFS file level.
+ //
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+
+ if (CurrentEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+ LocalEncapDataTemp = LocalEncapData->RightNode;
+ while (LocalEncapDataTemp != NULL) {
+ LocalEncapDataNext = LocalEncapDataTemp->NextNode;
+ if (LocalEncapDataNext != NULL && LocalEncapDataNext->NextNode != NULL) {
+
+ LibEncapNewFvFile(FvInFd, TemDir, LocalEncapDataTemp, 1, &ChildFileNameList);
+ ChildFileNameList->ParentLevel = LocalEncapDataTemp->Level -1;
+ if (FvInFd->ChildFvFFS == NULL) {
+ FvInFd->ChildFvFFS = ChildFileNameList;
+ } else {
+ NewFileNameList = FvInFd->ChildFvFFS;
+ while (NewFileNameList->Next != NULL) {
+ NewFileNameList = NewFileNameList->Next;
+ }
+ NewFileNameList->Next = ChildFileNameList;
+ }
+ }
+ LocalEncapDataTemp = LocalEncapDataTemp->RightNode;
+ }
+ }
+
+ if (LocalEncapData->Level > Level) {
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+ ParentLevel = Level;
+ ParentType = Type;
+ }
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ } else {
+ LocalEncapData = CurrentEncapData;
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->Level > Level) {
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+ ParentLevel = Level;
+ ParentType = Type;
+ }
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+
+ do {
+ switch (ParentType) {
+ case FMMT_ENCAP_TREE_FV:
+ OutputFileNameListFlag = TRUE;
+ EncapFvStart = 0;
+ for(OuterIndex=0;OutputFileNameListFlag;OuterIndex++){
+ //
+ // Generate FV.inf attributes.
+ //
+ InfFileName = LibFilenameStrExtended (strrchr(GenTempFile (),OS_SEP), TemDir, "inf");
+ FirstInFlag = TRUE;
+
+ InfFile = fopen (InfFileName, "wt+");
+
+ if (InfFile == NULL) {
+ Error ("FMMT", 0, 0004, "Could not open inf file %s to store FV information! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+
+ if (CurrentEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ } else {
+ LocalEncapData = CurrentEncapData;
+ }
+
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ //
+ // FV GUID Name memory allocation
+ //
+ FvGuidName = (CHAR8 *) malloc (255);
+
+ if (FvGuidName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+
+ memset(FvGuidName, '\0', 255);
+
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+ LocalEncapData->FvExtHeader->FvName.Data1,
+ LocalEncapData->FvExtHeader->FvName.Data2,
+ LocalEncapData->FvExtHeader->FvName.Data3,
+ LocalEncapData->FvExtHeader->FvName.Data4[0],
+ LocalEncapData->FvExtHeader->FvName.Data4[1],
+ LocalEncapData->FvExtHeader->FvName.Data4[2],
+ LocalEncapData->FvExtHeader->FvName.Data4[3],
+ LocalEncapData->FvExtHeader->FvName.Data4[4],
+ LocalEncapData->FvExtHeader->FvName.Data4[5],
+ LocalEncapData->FvExtHeader->FvName.Data4[6],
+ LocalEncapData->FvExtHeader->FvName.Data4[7]
+ );
+
+ } else {
+ FvGuidName = NULL;
+ }
+
+
+ if (ParentLevel == 1) {
+ Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, TRUE);
+ } else {
+ Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, FALSE);
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "generate FV INF file [Options] section failed.");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ Status = LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->Attributes, InfFile);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV header attribute failed");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (LocalEncapData->FvExtHeader != NULL) {
+ Status = LibGenExtFile(LocalEncapData->FvExtHeader, InfFile);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV EXT header failed");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ FvGuidName = NULL;
+ }
+
+ if (CurrentEncapData != NULL) {
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ if ((memcmp(&FvInFd->FfsAttuibutes[Index].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) {
+ SubFvId = Index;
+ break;
+ }
+ }
+ }
+ //
+ // Found FFSs from Fv structure.
+ //
+ FfsFoundFlag = FALSE;
+ IsRootFv = FALSE;
+ for (Index=0; Index <= FvInFd->FfsNumbers; Index++) {
+ if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == FALSE){
+ break;
+ }
+ if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE){
+ if (Index == EncapFvIndex) {
+ if (FirstInFlag) {
+ Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, TRUE);
+ FirstInFlag = FALSE;
+ } else {
+ Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, FALSE);
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ }
+ }
+
+ NewFileNameList = FvInFd->ChildFvFFS;
+ while (NewFileNameList != NULL && NewFileNameList -> FFSName != NULL) {
+ if (NewFileNameList -> ParentLevel == ParentLevel && Index == NewFileNameList->InFvId && NewFileNameList->FfsFoundFlag==TRUE) {
+ if (FirstInFlag) {
+ Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, TRUE);
+ FirstInFlag = FALSE;
+ } else {
+ Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, FALSE);
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ }
+ NewFileNameList = NewFileNameList->Next;
+ }
+
+ if (FvInFd->FfsAttuibutes[Index].IsHandle==TRUE) {
+ continue;
+ }
+ if (SubFvId > 0 && Index < SubFvId) {
+ continue;
+ }
+
+ //
+ // For the last level FFS, the level below FFSs we should not care the IsLeaf Flag.
+ //
+ if (IsLastLevelFfs) {
+ IsLeafFlagIgnore = TRUE;
+ } else {
+ IsLeafFlagIgnore = FvInFd->FfsAttuibutes[Index].IsLeaf;
+ }
+
+ if (FvInFd->FfsAttuibutes[Index].Level >= ParentLevel + 1 && IsLeafFlagIgnore) {
+ if (FirstInFlag) {
+ if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) {
+ FfsFoundFlag = TRUE;
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, TRUE);
+ FirstInFlag = FALSE;
+ FvInFd->FfsAttuibutes[Index].IsHandle=TRUE;
+ EncapFvStart = Index;
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (Index == 0) {
+ // Root FV need to include all FFS files.
+ IsRootFv = TRUE;
+ }
+ } else {
+ if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) {
+ FfsFoundFlag = TRUE;
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+ FvInFd->FfsAttuibutes[Index].IsHandle=TRUE;
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (Index == 0) {
+ // Root FV need to include all FFS files.
+ IsRootFv = TRUE;
+ }
+ }
+
+
+ //avoid a FV contain too many ffs files
+ if ((!IsRootFv) && (FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) && (FvInFd->FfsAttuibutes[Index+1].FvLevel <= FvInFd->MulFvLevel) &&
+ (FvInFd->FfsAttuibutes[Index].FvLevel != FvInFd->FfsAttuibutes[Index+1].FvLevel) && (ParentLevel != 1) && (FvInFd->FfsAttuibutes[Index].Level != FvInFd->FfsAttuibutes[Index+1].Level) &&
+ FvInFd->FfsAttuibutes[Index].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0x0){
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ break;
+ }else{
+ if (FvInFd->FfsAttuibutes[Index].Level != 0xFF){
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ }
+ }
+
+ }
+ }
+ // The Fv may has multiple level (> 2), when it is in the FvLevel == 2, we set the IsLastLevelFfs Flag
+ if (Index <=FvInFd->FfsNumbers && FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) {
+ if (FvInFd->FfsAttuibutes[Index].FvLevel == 2) {
+ IsLastLevelFfs = FALSE;
+ }
+ }
+ if (!FfsFoundFlag){
+ OutputFileNameListFlag = FALSE;
+ if (OuterIndex > 0){
+ fclose (InfFile);
+ break;
+ }
+ }
+ //
+ // Create FV
+ //
+ fclose (InfFile);
+
+ EncapFvIndex = EncapFvStart;
+
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "FV");
+
+ Status = LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileName, FvGuidName, IsLargeFile);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+ if (CurrentEncapData != NULL) {
+ OutputFileNameList->InFvId = EncapFvIndex;
+ if (EncapFvIndex > 0) {
+ memcpy(OutputFileNameList->UiName,FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiName, FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize);
+ OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize;
+ OutputFileNameList->Depex = FvInFd->FfsAttuibutes[EncapFvIndex - 1].Depex;
+ OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[EncapFvIndex - 1].DepexLen;
+ OutputFileNameList->FfsFoundFlag = FfsFoundFlag;
+ }
+ }
+ }
+ break;
+ case FMMT_ENCAP_TREE_FFS:
+
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ InputFileName = OutputFileNameList->FFSName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "ffs");
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ for(;LocalEncapData->NextNode != NULL;) {
+ if(LocalEncapData->FvExtHeader != NULL) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+
+ if (OutputFileNameList->UiNameSize > 0) {
+ TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp");
+ TmpFile = fopen(TmpFileName, "wb+");
+ if (TmpFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open tmp file %s to store UI section information! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ header = (OutputFileNameList->UiNameSize+4) | (EFI_SECTION_USER_INTERFACE << 24);
+ Index = 0;
+ while (header) {
+ SectionHeader[Index] = header % 0x100;
+ header /= 0x100;
+ Index ++;
+ }
+ InputFile = fopen(InputFileName, "rb+");
+ if (InputFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open input file %s! \n", "");
+ fclose(TmpFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(InputFile, 0, SEEK_SET);
+ fseek(InputFile, 0, SEEK_END);
+ InputFileSize = ftell(InputFile);
+ fseek(InputFile, 0, SEEK_SET);
+
+ Buffer = malloc(InputFileSize+OutputFileNameList->UiNameSize+4);
+ memcpy(Buffer, (CHAR16 *)SectionHeader, 4);
+ memcpy(Buffer + 4, (CHAR16 *)(OutputFileNameList->UiName), OutputFileNameList->UiNameSize);
+ if (fread(Buffer+4+OutputFileNameList->UiNameSize, 1, InputFileSize, InputFile) != InputFileSize) {
+ Error("FMMT", 0, 0004, "Could not open sec file %s to add UI section information! \n", "");
+ fclose(TmpFile);
+ fclose(InputFile);
+ free(Buffer);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fwrite(Buffer, 1, InputFileSize + OutputFileNameList->UiNameSize + 4, TmpFile);
+ free(Buffer);
+ fclose(TmpFile);
+ fclose(InputFile);
+ InputFileName = TmpFileName;
+ }
+ if (OutputFileNameList->DepexLen > 0) {
+ TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp");
+ TmpFile = fopen(TmpFileName, "wb+");
+ if (TmpFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open tmp file %s to store Depex section information! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ InputFile = fopen(InputFileName, "rb+");
+ if (InputFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open input file %s! \n", "");
+ fclose(TmpFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(InputFile, 0, SEEK_SET);
+ fseek(InputFile, 0, SEEK_END);
+ InputFileSize = ftell(InputFile);
+ fseek(InputFile, 0, SEEK_SET);
+ // make sure the section is 4 byte align
+ if (OutputFileNameList->DepexLen % 4 != 0) {
+ AlignN = 4 - OutputFileNameList->DepexLen % 4;
+ }
+ Buffer = malloc(InputFileSize + OutputFileNameList->DepexLen + AlignN);
+ memcpy(Buffer, OutputFileNameList->Depex, OutputFileNameList->DepexLen);
+ if (AlignN != 0) {
+ for (Index = 0; Index < AlignN; Index ++) {
+ memcpy(Buffer + OutputFileNameList->DepexLen + Index, AlignV, 1);
+ }
+ }
+ if (fread(Buffer + OutputFileNameList->DepexLen + AlignN, 1, InputFileSize, InputFile) != InputFileSize) {
+ Error("FMMT", 0, 0004, "Could not open sec file %s to add Depex section information! \n", "");
+ fclose(TmpFile);
+ fclose(InputFile);
+ free(Buffer);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fwrite(Buffer, 1, InputFileSize + OutputFileNameList->DepexLen + AlignN, TmpFile);
+ free(Buffer);
+ fclose(TmpFile);
+ fclose(InputFile);
+ InputFileName = TmpFileName;
+ }
+ for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) {
+ if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(LocalEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){
+ if (access(FvInFd->FfsAttuibutes[Id].FfsName, 0) != -1) {
+ Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[Id].FfsName);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ memset(FvInFd->FfsAttuibutes[Id].FfsName, '\0', _MAX_PATH);
+ FvInFd->FfsAttuibutes[Id].Level = 0xFF;
+ break;
+ }
+ }
+ }
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapDataTemp = LocalEncapData->NextNode;
+ if ((LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_GUIDED_SECTION) || (LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_COMPRESS_SECTION)) {
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, "1");
+ }
+ else{
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr);
+ }
+ }
+ else{
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr);
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ free(LocalEncapData->FvExtHeader);
+ LocalEncapData->FvExtHeader = NULL;
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+ OutputFileNameList->IsFFS = TRUE;
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ case FMMT_ENCAP_TREE_GUIDED_SECTION:
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ //
+ // Create the guided section original data, do compress operation.
+ //
+ InputFileName = OutputFileNameList->FFSName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "compressed");
+
+ //
+ // Use the guided section header guid to find out compress application name.
+ //
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ (EFI_GUID *)LocalEncapData->Data
+ );
+ GuidDataOffset = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID));
+ GuidAttributes = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID) + sizeof (UINT16));
+
+ Status = LibCreateGuidedSectionOriginalData (InputFileName, ExtractionTool, OutputFileName);
+
+ if (EFI_ERROR (Status) || GuidDataOffset < sizeof (EFI_GUID_DEFINED_SECTION)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Compress guided data failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ GuidDataOffset = GuidDataOffset - sizeof (EFI_GUID_DEFINED_SECTION);
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "guided");
+
+ Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_GUID_DEFINED, OutputFileName, NULL, NULL, LibFmmtGuidToStr((EFI_GUID *)LocalEncapData->Data), GuidDataOffset, GuidAttributes, NULL);
+ OutFile = fopen(OutputFileName, "rb+");
+ if (OutFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open the file %s! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(OutFile, 0, SEEK_SET);
+ fseek(OutFile, 0, SEEK_END);
+ OutputFileSize = ftell(OutFile);
+ fclose(OutFile);
+ if (OutputFileSize > LargeFileSize) {
+ IsLargeFile = TRUE;
+ }
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate guided section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ case FMMT_ENCAP_TREE_COMPRESS_SECTION:
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ InputFileName = OutputFileNameList->FFSName;
+
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "comsec");
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ Status = LibGenCompressedSection (InputFileName, OutputFileName, *(UINT8 *)(LocalEncapData->Data));
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate compressed section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ case FMMT_ENCAP_TREE_FV_SECTION:
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ InputFileName = OutputFileNameList->FFSName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, 0, 0, NULL);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ //
+ // Make it alignment.
+ //
+ Status = LibCreateFfsSection(FvInFd, InputFileName, NULL, 0, OutputFileName, NULL, NULL, NULL, 0, 0, NULL);
+ OutFile = fopen(OutputFileName, "rb+");
+ if (OutFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open the file %s! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(OutFile, 0, SEEK_SET);
+ fseek(OutFile, 0, SEEK_END);
+ OutputFileSize = ftell(OutFile);
+ fclose(OutFile);
+ if (OutputFileSize > LargeFileSize) {
+ IsLargeFile = TRUE;
+ }
+
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ default:
+ for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) {
+ if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){
+ FvInFd->FfsAttuibutes[Id].IsHandle = TRUE;
+ memcpy(OutputFileNameList->UiName, FvInFd->FfsAttuibutes[Id].UiName, FvInFd->FfsAttuibutes[Id].UiNameSize);
+ OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[Id].UiNameSize;
+ OutputFileNameList->FFSName = FvInFd->FfsAttuibutes[Id].FfsName;
+ OutputFileNameList->Depex = FvInFd->FfsAttuibutes[Id].Depex;
+ OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[Id].DepexLen;
+ OutputFileNameList->FfsFoundFlag = TRUE;
+ OutputFileNameList->IsFFS = TRUE;
+ OutputFileNameList->InFvId = Id;
+ *OutputFile = OutputFileNameList;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (CurrentEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ } else {
+ if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE) {
+ *OutputFile = OutputFileNameList;
+ return EFI_SUCCESS;
+ }
+ LocalEncapData = CurrentEncapData;
+ }
+ ParentLevel -= 1;
+
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ LocalEncapDataTemp = LocalEncapData->NextNode;
+ if ((LocalEncapDataTemp != NULL) && (LocalEncapDataTemp->Level == ParentLevel)) {
+ ParentType = LocalEncapDataTemp->Type;
+ break;
+ }
+ ParentType = LocalEncapData->Type;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ } while (ParentLevel != Level_Break);
+
+ *OutputFile = OutputFileNameList;
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+LibFindFvInEncapData (
+ ENCAP_INFO_DATA *EncapData,
+ UINT8 *Index
+)
+{
+ ENCAP_INFO_DATA *LocalEncapData;
+ LocalEncapData = EncapData;
+ if (LocalEncapData == NULL) {
+ Error("FMMT", 0, 0005, "error while find FV in Encapulate buffer", "Invalid parameters.");
+ return EFI_INVALID_PARAMETER;
+ }
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->RightNode != NULL) {
+ LibFindFvInEncapData (LocalEncapData->RightNode, Index);
+ }
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) {
+ (*Index)++;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibLocateFvViaFvId (
+ IN FIRMWARE_DEVICE *FdData,
+ IN CHAR8 *FvId,
+ IN OUT FV_INFORMATION **FvInFd
+)
+{
+ UINT8 FvIndex1;
+ UINT8 FvIndex2;
+ BOOLEAN FvFoundFlag;
+ CHAR8* FvGuidName;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataRight;
+ ENCAP_INFO_DATA *LocalEncapDataNext;
+ FvIndex1 = 0;
+ FvIndex2 = 0;
+ FvFoundFlag = FALSE;
+ FvGuidName = NULL;
+ LocalEncapDataNext = NULL;
+ LocalEncapDataRight = NULL;
+
+ if (FdData == NULL || FvId == NULL || FvInFd == NULL || FdData->Fv == NULL) {
+ Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid parameters.");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FvInFd = FdData->Fv;
+
+ if (strlen(FvId) < 3) {
+ Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!");
+ return EFI_ABORTED;
+ }
+
+ FvGuidName = (CHAR8 *) malloc (255);
+ if (FvGuidName == NULL) {
+ Error ("FMMT", 0, 0005, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ memset(FvGuidName, '\0', 255);
+ LocalEncapData = NULL;
+
+ if (strlen(FvId) == 36) {
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvExtHeader) != NULL) {
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ (*FvInFd)->FvExtHeader->FvName.Data1,
+ (*FvInFd)->FvExtHeader->FvName.Data2,
+ (*FvInFd)->FvExtHeader->FvName.Data3,
+ (*FvInFd)->FvExtHeader->FvName.Data4[0],
+ (*FvInFd)->FvExtHeader->FvName.Data4[1],
+ (*FvInFd)->FvExtHeader->FvName.Data4[2],
+ (*FvInFd)->FvExtHeader->FvName.Data4[3],
+ (*FvInFd)->FvExtHeader->FvName.Data4[4],
+ (*FvInFd)->FvExtHeader->FvName.Data4[5],
+ (*FvInFd)->FvExtHeader->FvName.Data4[6],
+ (*FvInFd)->FvExtHeader->FvName.Data4[7]);
+ if (strcmp(FvGuidName, FvId) == 0) {
+ FvId = (*FvInFd)->FvName;
+ break;
+ }
+ }
+ if ((*FvInFd)->MulFvLevel > 1) {
+ LocalEncapData = (*FvInFd) -> EncapData;
+ LocalEncapData = LocalEncapData->NextNode;
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->RightNode != NULL) {
+ LocalEncapDataRight = LocalEncapData->RightNode;
+ while (LocalEncapDataRight !=NULL) {
+ if (LocalEncapDataRight->NextNode != NULL) {
+ LocalEncapDataNext = LocalEncapDataRight->NextNode;
+ while (LocalEncapDataNext != NULL) {
+ if (LocalEncapDataNext->Type == FMMT_ENCAP_TREE_FV) {
+ if (LocalEncapDataNext->FvExtHeader != NULL) {
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ LocalEncapDataNext->FvExtHeader->FvName.Data1,
+ LocalEncapDataNext->FvExtHeader->FvName.Data2,
+ LocalEncapDataNext->FvExtHeader->FvName.Data3,
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[0],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[1],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[2],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[3],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[4],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[5],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[6],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[7]);
+ if (strcmp(FvGuidName, FvId) == 0)
+ {
+ sprintf(FvId, "%s%d", "FV", LocalEncapDataNext->FvId - 1);
+ break;
+ }
+
+ }
+ }
+ LocalEncapDataNext = LocalEncapDataNext->NextNode;
+ }
+ }
+ LocalEncapDataRight = LocalEncapDataRight->RightNode;
+ }
+ }
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) {
+ if (LocalEncapData->FvExtHeader != NULL) {
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ LocalEncapData->FvExtHeader->FvName.Data1,
+ LocalEncapData->FvExtHeader->FvName.Data2,
+ LocalEncapData->FvExtHeader->FvName.Data3,
+ LocalEncapData->FvExtHeader->FvName.Data4[0],
+ LocalEncapData->FvExtHeader->FvName.Data4[1],
+ LocalEncapData->FvExtHeader->FvName.Data4[2],
+ LocalEncapData->FvExtHeader->FvName.Data4[3],
+ LocalEncapData->FvExtHeader->FvName.Data4[4],
+ LocalEncapData->FvExtHeader->FvName.Data4[5],
+ LocalEncapData->FvExtHeader->FvName.Data4[6],
+ LocalEncapData->FvExtHeader->FvName.Data4[7]);
+
+ if (strcmp(FvGuidName, FvId) == 0) {
+ sprintf(FvId, "%s%d", "FV", LocalEncapData->FvId - 1);
+ break;
+ }
+ }
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ }
+ *FvInFd = FdData->Fv;
+ FvIndex1 = (UINT8) atoi (FvId + 2);
+
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvName) != NULL) {
+ FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+ LocalEncapData = (*FvInFd)->EncapData;
+ LibFindFvInEncapData (LocalEncapData, &FvIndex2);
+
+ if ((FvIndex2 - 1 >= FvIndex1)) {
+ FvFoundFlag = TRUE;
+ break;
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ //
+ // The specified FV id has issue, can not find the FV in FD.
+ //
+ if (!FvFoundFlag) {
+ Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!");
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+)
+{
+ EFI_GUID Guid;
+ STRING_LIST *Tool;
+ GUID_SEC_TOOL_ENTRY *FirstGuidTool;
+ GUID_SEC_TOOL_ENTRY *LastGuidTool;
+ GUID_SEC_TOOL_ENTRY *NewGuidTool;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
+ "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
+ "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
+ "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
+ "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
+ };
+
+ Tool = NULL;
+ FirstGuidTool = NULL;
+ LastGuidTool = NULL;
+ NewGuidTool = NULL;
+ Index = 0;
+
+ for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
+ Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
+ if ((Tool != NULL) &&
+ (Tool->Count == 3)
+ ) {
+ Status = StringToGuid (Tool->Strings[0], &Guid);
+ if (!EFI_ERROR (Status)) {
+ NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
+ if (NewGuidTool != NULL) {
+ memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
+ NewGuidTool->Name = CloneString(Tool->Strings[1]);
+ NewGuidTool->Path = CloneString(Tool->Strings[2]);
+ NewGuidTool->Next = NULL;
+ } else {
+ printf ("Error while allocate resource! \n");
+ FreeStringList (Tool);
+ return NULL;
+ }
+ if (FirstGuidTool == NULL) {
+ FirstGuidTool = NewGuidTool;
+ } else {
+ LastGuidTool->Next = NewGuidTool;
+ }
+ LastGuidTool = NewGuidTool;
+ }
+ } else {
+ fprintf (stdout, "Error");
+ }
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ Tool = NULL;
+ }
+ }
+ return FirstGuidTool;
+}
diff --git a/BaseTools/Source/C/FMMT/Rebase.c b/BaseTools/Source/C/FMMT/Rebase.c
new file mode 100644
index 0000000000..d32217d18c
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/Rebase.c
@@ -0,0 +1,846 @@
+/** @file
+
+ Library to rebase PE image.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Rebase.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <PeCoffLib.h>
+#include <CommonLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <FvLib.h>
+#include "EfiUtilityMsgs.h"
+
+static
+EFI_STATUS
+FfsRebaseImageRead(
+IN VOID *FileHandle,
+IN UINTN FileOffset,
+IN OUT UINT32 *ReadSize,
+OUT VOID *Buffer
+);
+
+EFI_STATUS
+RebaseFfs(
+IN OUT UINT64 BaseAddress,
+IN CHAR8 *FileName,
+IN OUT EFI_FFS_FILE_HEADER *FfsFile,
+IN UINTN XipOffset
+)
+/*++
+
+Routine Description:
+
+This function determines if a file is XIP and should be rebased. It will
+rebase any PE32 sections found in the file using the base address.
+
+Arguments:
+
+FvInfo A pointer to FV_INFO struture.
+FileName Ffs File PathName
+FfsFile A pointer to Ffs file image.
+XipOffset The offset address to use for rebasing the XIP file image.
+
+Returns:
+
+EFI_SUCCESS The image was properly rebased.
+EFI_INVALID_PARAMETER An input parameter is invalid.
+EFI_ABORTED An error occurred while rebasing the input file image.
+EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+EFI_NOT_FOUND No compressed sections could be found.
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext;
+ EFI_PHYSICAL_ADDRESS XipBase;
+ EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;
+ UINTN Index;
+ EFI_FILE_SECTION_POINTER CurrentPe32Section;
+ EFI_FFS_FILE_STATE SavedState;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_TE_IMAGE_HEADER *TEImageHeader;
+ UINT8 *MemoryImagePointer;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+ CHAR8 PeFileName[MAX_LONG_FILE_PATH];
+ CHAR8 *Cptr;
+ FILE *PeFile;
+ UINT8 *PeFileBuffer;
+ UINT32 PeFileSize;
+ CHAR8 *PdbPointer;
+ UINT32 FfsHeaderSize;
+ UINT32 CurSecHdrSize;
+ CHAR8 *LongFilePathName;
+
+ Index = 0;
+ MemoryImagePointer = NULL;
+ TEImageHeader = NULL;
+ ImgHdr = NULL;
+ SectionHeader = NULL;
+ Cptr = NULL;
+ PeFile = NULL;
+ PeFileBuffer = NULL;
+
+ //
+ // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
+ //
+ if (BaseAddress == 0) {
+ return EFI_SUCCESS;
+ }
+
+ XipBase = BaseAddress + XipOffset;
+
+ //
+ // We only process files potentially containing PE32 sections.
+ //
+ switch (FfsFile->Type) {
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+ case EFI_FV_FILETYPE_DRIVER:
+ case EFI_FV_FILETYPE_DXE_CORE:
+ break;
+ case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
+ //
+ // Rebase the inside FvImage.
+ //
+ GetChildFvFromFfs (BaseAddress, FfsFile, XipOffset);
+
+ //
+ // Search PE/TE section in FV sectin.
+ //
+ break;
+ default:
+ return EFI_SUCCESS;
+ }
+
+ FfsHeaderSize = GetFfsHeaderLength(FfsFile);
+ //
+ // Rebase each PE32 section
+ //
+ Status = EFI_SUCCESS;
+ for (Index = 1;; Index++) {
+ //
+ // Init Value
+ //
+ NewPe32BaseAddress = 0;
+
+ //
+ // Find Pe Image
+ //
+ Status = GetSectionByType(FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+ //
+ // Initialize context
+ //
+ memset(&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+
+ //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+ // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+ // mArm = TRUE;
+ //}
+
+ //
+ // Keep Image Context for PE image in FV
+ //
+ memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+ //
+ // Get File PdbPointer
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+ if (PdbPointer == NULL) {
+ PdbPointer = FileName;
+ }
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);
+
+ //
+ // Calculate the PE32 base address, based on file type
+ //
+ switch (FfsFile->Type) {
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+ //
+ // Check if section-alignment and file-alignment match or not
+ //
+ if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+ //
+ // Xip module has the same section alignment and file alignment.
+ //
+ Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+ return EFI_ABORTED;
+ }
+ //
+ // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
+ //
+ if (ImageContext.RelocationsStripped) {
+ //
+ // Construct the original efi file Name
+ //
+ if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+ Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+ return EFI_ABORTED;
+ }
+ strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+ PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+ Cptr = PeFileName + strlen(PeFileName);
+ while (*Cptr != '.') {
+ Cptr--;
+ }
+ if (*Cptr != '.') {
+ Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ return EFI_ABORTED;
+ }
+ else {
+ *(Cptr + 1) = 'e';
+ *(Cptr + 2) = 'f';
+ *(Cptr + 3) = 'i';
+ *(Cptr + 4) = '\0';
+ }
+ LongFilePathName = LongFilePath(PeFileName);
+ if (LongFilePathName == NULL) {
+ Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+ return EFI_ABORTED;
+ }
+ PeFile = fopen(LongFilePathName, "rb");
+ if (PeFile == NULL) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ //return EFI_ABORTED;
+ break;
+ }
+ //
+ // Get the file size
+ //
+ PeFileSize = _filelength(fileno(PeFile));
+ PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+ if (PeFileBuffer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ fclose(PeFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read Pe File
+ //
+ fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+ //
+ // close file
+ //
+ fclose(PeFile);
+ //
+ // Handle pointer to the original efi image.
+ //
+ ImageContext.Handle = PeFileBuffer;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+ ImageContext.RelocationsStripped = FALSE;
+ }
+
+ NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+ break;
+
+ case EFI_FV_FILETYPE_DRIVER:
+ case EFI_FV_FILETYPE_DXE_CORE:
+ //
+ // Check if section-alignment and file-alignment match or not
+ //
+ if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+ //
+ // Xip module has the same section alignment and file alignment.
+ //
+ Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+ return EFI_ABORTED;
+ }
+ NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+ break;
+
+ default:
+ //
+ // Not supported file type
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Relocation doesn't exist
+ //
+ if (ImageContext.RelocationsStripped) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ continue;
+ }
+
+ //
+ // Relocation exist and rebase
+ //
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy Relocated data to raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(
+ (UINTN)ImgHdr +
+ sizeof (UINT32)+
+ sizeof (EFI_IMAGE_FILE_HEADER)+
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
+ CopyMem(
+ (UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+
+ free((VOID *)MemoryImagePointer);
+ MemoryImagePointer = NULL;
+ if (PeFileBuffer != NULL) {
+ free(PeFileBuffer);
+ PeFileBuffer = NULL;
+ }
+
+ //
+ // Update Image Base Address
+ //
+ if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32)NewPe32BaseAddress;
+ }
+ else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
+ }
+ else {
+ Error(NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
+ ImgHdr->Pe32.OptionalHeader.Magic,
+ FileName
+ );
+ return EFI_ABORTED;
+ }
+
+ //
+ // Now update file checksum
+ //
+ if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ SavedState = FfsFile->State;
+ FfsFile->IntegrityCheck.Checksum.File = 0;
+ FfsFile->State = 0;
+ FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+ (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+ GetFfsFileLength(FfsFile) - FfsHeaderSize
+ );
+ FfsFile->State = SavedState;
+ }
+
+ }
+
+ if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
+ FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
+ FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
+ FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&
+ FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ ) {
+ //
+ // Only Peim code may have a TE section
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Now process TE sections
+ //
+ for (Index = 1;; Index++) {
+ NewPe32BaseAddress = 0;
+
+ //
+ // Find Te Image
+ //
+ Status = GetSectionByType(FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+
+ CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+ //
+ // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
+ // by GenTEImage
+ //
+ TEImageHeader = (EFI_TE_IMAGE_HEADER *)((UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+
+ //
+ // Initialize context, load image info.
+ //
+ memset(&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *)TEImageHeader;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+
+ //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+ // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+ // mArm = TRUE;
+ //}
+
+ //
+ // Keep Image Context for TE image in FV
+ //
+ memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+ //
+ // Get File PdbPointer
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+ if (PdbPointer == NULL) {
+ PdbPointer = FileName;
+ }
+ //
+ // Set new rebased address.
+ //
+ NewPe32BaseAddress = XipBase + (UINTN)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
+ - TEImageHeader->StrippedSize - (UINTN)FfsFile;
+
+ //
+ // if reloc is stripped, try to get the original efi image to get reloc info.
+ //
+ if (ImageContext.RelocationsStripped) {
+ //
+ // Construct the original efi file name
+ //
+ if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+ Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+ return EFI_ABORTED;
+ }
+ strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+ PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+ Cptr = PeFileName + strlen(PeFileName);
+ while (*Cptr != '.') {
+ Cptr--;
+ }
+
+ if (*Cptr != '.') {
+ Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ return EFI_ABORTED;
+ }
+ else {
+ *(Cptr + 1) = 'e';
+ *(Cptr + 2) = 'f';
+ *(Cptr + 3) = 'i';
+ *(Cptr + 4) = '\0';
+ }
+
+ LongFilePathName = LongFilePath(PeFileName);
+ if (LongFilePathName == NULL) {
+ Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+ return EFI_ABORTED;
+ }
+ PeFile = fopen(LongFilePathName, "rb");
+ if (PeFile == NULL) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ //return EFI_ABORTED;
+ }
+ else {
+ //
+ // Get the file size
+ //
+ PeFileSize = _filelength(fileno(PeFile));
+ PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+ if (PeFileBuffer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ fclose(PeFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read Pe File
+ //
+ fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+ //
+ // close file
+ //
+ fclose(PeFile);
+ //
+ // Append reloc section into TeImage
+ //
+ ImageContext.Handle = PeFileBuffer;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+ ImageContext.RelocationsStripped = FALSE;
+ }
+ }
+ //
+ // Relocation doesn't exist
+ //
+ if (ImageContext.RelocationsStripped) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ continue;
+ }
+
+ //
+ // Relocation exist and rebase
+ //
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+ //
+ // Reloacate TeImage
+ //
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy the relocated image into raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(TEImageHeader + 1);
+ for (Index = 0; Index < TEImageHeader->NumberOfSections; Index++, SectionHeader++) {
+ if (!ImageContext.IsTeImage) {
+ CopyMem(
+ (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+ else {
+ CopyMem(
+ (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+ }
+
+ //
+ // Free the allocated memory resource
+ //
+ free((VOID *)MemoryImagePointer);
+ MemoryImagePointer = NULL;
+ if (PeFileBuffer != NULL) {
+ free(PeFileBuffer);
+ PeFileBuffer = NULL;
+ }
+
+ //
+ // Update Image Base Address
+ //
+ TEImageHeader->ImageBase = NewPe32BaseAddress;
+
+ //
+ // Now update file checksum
+ //
+ if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ SavedState = FfsFile->State;
+ FfsFile->IntegrityCheck.Checksum.File = 0;
+ FfsFile->State = 0;
+ FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+ (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+ GetFfsFileLength(FfsFile) - FfsHeaderSize
+ );
+ FfsFile->State = SavedState;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FfsRebaseImageRead(
+IN VOID *FileHandle,
+IN UINTN FileOffset,
+IN OUT UINT32 *ReadSize,
+OUT VOID *Buffer
+)
+/*++
+
+Routine Description:
+
+Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+
+FileHandle - The handle to the PE/COFF file
+
+FileOffset - The offset, in bytes, into the file to read
+
+ReadSize - The number of bytes to read from the file starting at FileOffset
+
+Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+
+EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINT32 Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetChildFvFromFfs (
+ IN UINT64 BaseAddress,
+ IN EFI_FFS_FILE_HEADER *FfsFile,
+ IN UINTN XipOffset
+ )
+/*++
+
+Routine Description:
+
+ This function gets all child FvImages in the input FfsFile, and records
+ their base address to the parent image.
+
+Arguments:
+ FvInfo A pointer to FV_INFO struture.
+ FfsFile A pointer to Ffs file image that may contain FvImage.
+ XipOffset The offset address to the parent FvImage base.
+
+Returns:
+
+ EFI_SUCCESS Base address of child Fv image is recorded.
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_FILE_SECTION_POINTER SubFvSection;
+ EFI_FIRMWARE_VOLUME_HEADER *SubFvImageHeader;
+ EFI_PHYSICAL_ADDRESS SubFvBaseAddress;
+ EFI_FIRMWARE_VOLUME_HEADER *OrigFvHeader;
+ UINT32 OrigFvLength;
+ EFI_PHYSICAL_ADDRESS OrigFvBaseAddress;
+ EFI_FFS_FILE_HEADER *CurrentFile;
+
+ //
+ // Initialize FV library, saving previous values
+ //
+ OrigFvHeader = NULL;
+ GetFvHeader (&OrigFvHeader, &OrigFvLength);
+ OrigFvBaseAddress = BaseAddress;
+ for (Index = 1;; Index++) {
+ //
+ // Find FV section
+ //
+ Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));
+
+ //
+ // Rebase on Flash
+ //
+ SubFvBaseAddress = OrigFvBaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;
+ //mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;
+ BaseAddress = SubFvBaseAddress;
+ InitializeFvLib(SubFvImageHeader, (UINT32) SubFvImageHeader->FvLength);
+
+ Status = GetNextFile (NULL, &CurrentFile);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error parsing FV image", "FFS file can't be found");
+ continue;
+ }
+ while (CurrentFile) {
+ RebaseFfs (BaseAddress, "", CurrentFile, (UINTN) CurrentFile - (UINTN) SubFvImageHeader);
+ Status = GetNextFile (CurrentFile, &CurrentFile);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ BaseAddress = OrigFvBaseAddress;
+ if (OrigFvHeader != NULL) {
+ InitializeFvLib(OrigFvHeader, OrigFvLength);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetPe32Info (
+ IN UINT8 *Pe32,
+ OUT UINT32 *EntryPoint,
+ OUT UINT32 *BaseOfCode,
+ OUT UINT16 *MachineType
+ )
+/*++
+
+Routine Description:
+
+ Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
+ See EfiImage.h for machine types. The entry point offset is from the beginning
+ of the PE32 buffer passed in.
+
+Arguments:
+
+ Pe32 Beginning of the PE32.
+ EntryPoint Offset from the beginning of the PE32 to the image entry point.
+ BaseOfCode Base address of code.
+ MachineType Magic number for the machine type.
+
+Returns:
+
+ EFI_SUCCESS Function completed successfully.
+ EFI_ABORTED Error encountered.
+ EFI_INVALID_PARAMETER A required parameter was NULL.
+ EFI_UNSUPPORTED The operation is unsupported.
+
+--*/
+{
+ EFI_IMAGE_DOS_HEADER *DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_TE_IMAGE_HEADER *TeHeader;
+
+ //
+ // Verify input parameters
+ //
+ if (Pe32 == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // First check whether it is one TE Image.
+ //
+ TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
+ if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ //
+ // By TeImage Header to get output
+ //
+ *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+ *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+ *MachineType = TeHeader->Machine;
+ } else {
+
+ //
+ // Then check whether
+ // First is the DOS header
+ //
+ DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
+
+ //
+ // Verify DOS header is expected
+ //
+ if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Immediately following is the NT header.
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
+
+ //
+ // Verify NT header is expected
+ //
+ if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get output
+ //
+ *EntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
+ *BaseOfCode = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
+ *MachineType = ImgHdr->Pe32.FileHeader.Machine;
+ }
+
+ //
+ // Verify machine type is supported
+ //
+ if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&
+ (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {
+ Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/BaseTools/BinWrappers/PosixLike/FMMT b/BaseTools/BinWrappers/PosixLike/FMMT
new file mode 100755
index 0000000000..a244ecc095
--- /dev/null
+++ b/BaseTools/BinWrappers/PosixLike/FMMT
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
+dir=$(dirname "$full_cmd")
+cmd=${full_cmd##*/}
+
+if [ -n "$WORKSPACE" ] && [ -e "$WORKSPACE/Conf/BaseToolsCBinaries" ]
+then
+ exec "$WORKSPACE/Conf/BaseToolsCBinaries/$cmd"
+elif [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/Source/C" ]
+then
+ if [ ! -e "$EDK_TOOLS_PATH/Source/C/bin/$cmd" ]
+ then
+ echo "BaseTools C Tool binary was not found ($cmd)"
+ echo "You may need to run:"
+ echo " make -C $EDK_TOOLS_PATH/Source/C"
+ else
+ exec "$EDK_TOOLS_PATH/Source/C/bin/$cmd" "$@"
+ fi
+elif [ -e "$dir/../../Source/C/bin/$cmd" ]
+then
+ exec "$dir/../../Source/C/bin/$cmd" "$@"
+else
+ echo "Unable to find the real '$cmd' to run"
+ echo "This message was printed by"
+ echo " $0"
+ exit 127
+fi
+
diff --git a/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h
new file mode 100644
index 0000000000..ec8e3eaba0
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h
@@ -0,0 +1,479 @@
+/** @file
+
+ Structures and functions declaration.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BIN_FILE_MANAGER_
+#define _BIN_FILE_MANAGER_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <FvLib.h>
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Common/PiFirmwareFile.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "ParseInf.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "Compress.h"
+#include "Decompress.h"
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#ifdef __GNUC__
+#define OS_SEP '/'
+#define OS_SEP_STR "/"
+#define COPY_STR "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR "rm -r \"%s\" > /dev/null"
+#define DEL_STR "rm \"%s\" > /dev/null"
+#else
+#define OS_SEP '\\'
+#define OS_SEP_STR "\\"
+#define COPY_STR "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR "del \"%s\" > NUL"
+#endif
+
+#define UTILITY_NAME "Firmware Module Management Tool(FMMT)"
+#define UTILITY_SHORT_NAME "FMMT"
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 23
+#define MAX_BASENAME_LEN 60 // not good to HardCode, but let's be reasonable
+#define EFI_SECTION_ERROR EFIERR (100)
+//
+// The maximum number of Pad file guid entries.
+//
+#define MAX_NUMBER_OF_PAD_FILE_GUIDS 1024
+
+//
+// The maximum number of block map entries supported by the library
+//
+#define MAX_NUMBER_OF_FV_BLOCKS 100
+
+
+//
+// The maximum number of sections in an FFS file.
+//
+#define MAX_NUMBER_OF_SECTION_IN_FFS 100
+
+//
+// The maximum number of files in the FV supported by the library
+//
+#define MAX_NUMBER_OF_FILES_IN_FV 1000
+#define MAX_NUMBER_OF_FILES_IN_CAP 1000
+
+
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE is only used by DXE driver.
+///
+#define EFI_DEP_BEFORE 0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER is only used by DXE driver.
+///
+#define EFI_DEP_AFTER 0x01
+
+#define EFI_DEP_PUSH 0x02
+#define EFI_DEP_AND 0x03
+#define EFI_DEP_OR 0x04
+#define EFI_DEP_NOT 0x05
+#define EFI_DEP_TRUE 0x06
+#define EFI_DEP_FALSE 0x07
+#define EFI_DEP_END 0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR 0x09
+
+//
+// INF file strings
+//
+#define OPTIONS_SECTION_STRING "[options]"
+#define ATTRIBUTES_SECTION_STRING "[attributes]"
+#define FILES_SECTION_STRING "[files]"
+#define FV_BASE_ADDRESS_STRING "[FV_BASE_ADDRESS]"
+
+//
+// Options section
+//
+#define EFI_FV_BASE_ADDRESS_STRING "EFI_BASE_ADDRESS"
+#define EFI_FV_FILE_NAME_STRING "EFI_FILE_NAME"
+#define EFI_NUM_BLOCKS_STRING "EFI_NUM_BLOCKS"
+#define EFI_BLOCK_SIZE_STRING "EFI_BLOCK_SIZE"
+#define EFI_GUID_STRING "EFI_GUID"
+#define EFI_FV_FILESYSTEMGUID_STRING "EFI_FV_GUID"
+#define EFI_FV_NAMEGUID_STRING "EFI_FVNAME_GUID"
+#define EFI_CAPSULE_GUID_STRING "EFI_CAPSULE_GUID"
+#define EFI_CAPSULE_HEADER_SIZE_STRING "EFI_CAPSULE_HEADER_SIZE"
+#define EFI_CAPSULE_FLAGS_STRING "EFI_CAPSULE_FLAGS"
+#define EFI_CAPSULE_VERSION_STRING "EFI_CAPSULE_VERSION"
+
+#define EFI_FV_TOTAL_SIZE_STRING "EFI_FV_TOTAL_SIZE"
+#define EFI_FV_TAKEN_SIZE_STRING "EFI_FV_TAKEN_SIZE"
+#define EFI_FV_SPACE_SIZE_STRING "EFI_FV_SPACE_SIZE"
+
+
+typedef UINT32 FMMT_ENCAP_TYPE;
+
+#define MAX_LEVEL_IN_FV_FILE 32
+
+//
+// Types of FMMT_ENCAP_TREENODE_TYPE
+//
+#define FMMT_ENCAP_TREE_FV 0x1
+#define FMMT_ENCAP_TREE_FFS 0x2
+#define FMMT_ENCAP_TREE_GUIDED_SECTION 0x3
+#define FMMT_ENCAP_TREE_COMPRESS_SECTION 0x4
+#define FMMT_ENCAP_TREE_FV_SECTION 0x5
+
+extern EFI_HANDLE mParsedGuidedSectionTools;
+
+
+#define TEMP_DIR_NAME "FmmtTemp"
+
+//
+// Structure to keep a list of GUID-To-BaseNames
+//
+typedef struct _GUID_TO_BASENAME {
+ struct _GUID_TO_BASENAME *Next;
+ INT8 Guid[PRINTED_GUID_BUFFER_SIZE];
+ INT8 BaseName[MAX_BASENAME_LEN];
+} GUID_TO_BASENAME;
+
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+ EFI_GUID Guid;
+ CHAR8* Name;
+ CHAR8* Path;
+ struct _GUID_SEC_TOOL_ENTRY *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+
+//
+// Private data types
+//
+//
+// Component information
+//
+typedef struct {
+ UINTN Size;
+ CHAR8 ComponentName[_MAX_PATH];
+} COMPONENT_INFO;
+
+typedef struct {
+ CHAR8 FfsName[_MAX_PATH];
+
+ //
+ // UI Name for this FFS file, if has.
+ //
+ CHAR16 UiName[_MAX_PATH];
+ UINT32 UiNameSize;
+ //
+ // Total section number in this FFS.
+ //
+ UINT32 TotalSectionNum;
+
+ //
+ // Describe the position of the FFS file.
+ //
+ UINT8 Level;
+ //
+ // If this FFS has no encapsulate section, this flag will set to True.
+ //
+ BOOLEAN IsLeaf;
+ //
+ // Section type for each section in FFS.
+ //
+ EFI_SECTION_TYPE SectionType[MAX_NUMBER_OF_SECTION_IN_FFS];
+ //
+ // Offset relative to current FV
+ //
+ UINT32 Offset;
+ UINT8 FvLevel;
+ EFI_GUID GuidName;
+ UINT8 *Depex;
+ UINT32 DepexLen;
+ BOOLEAN IsHandle;
+ BOOLEAN IsFvStart;
+ BOOLEAN IsFvEnd;
+}FFS_ATTRIBUTES;
+
+
+typedef struct __ENCAP_INFO_DATA{
+ //
+ // Now Level
+ //
+ UINT8 Level;
+
+ //
+ // Encapsulate type.
+ //
+ FMMT_ENCAP_TYPE Type;
+
+ //
+ // Data, if it's FV, should be FV header.
+ //
+ VOID *Data;
+
+ //
+ //FvId, match FvId with FvGuidName.
+ //
+ UINT8 FvId;
+
+ //
+ // if FV ExtHeaderOffset not to zero, should also have FvExtHeader information
+ //
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+ CHAR16 UiName[_MAX_PATH];
+ UINT32 UiNameSize;
+ UINT8 *Depex;
+ UINT32 DepexLen;
+
+ //
+ // Next node.
+ //
+ struct __ENCAP_INFO_DATA *NextNode;
+
+ //
+ // Right node.
+ //
+ struct __ENCAP_INFO_DATA *RightNode;
+} ENCAP_INFO_DATA;
+
+typedef struct _FFS_INFOMATION{
+ CHAR8 *FFSName;
+ UINT32 InFvId;
+ UINT8 ParentLevel;
+ BOOLEAN IsFFS;
+ CHAR16 UiName[_MAX_PATH];
+ UINT32 UiNameSize;
+ UINT8 *Depex;
+ UINT32 DepexLen;
+ BOOLEAN FfsFoundFlag;
+ struct _FFS_INFOMATION *Next;
+} FFS_INFORMATION;
+
+//
+// FV and capsule information holder
+//
+typedef struct _FV_INFOMATION{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+ UINT32 ImageAddress;
+ UINT32 FfsNumbers;
+ CHAR8 FvName[_MAX_PATH];
+ EFI_FV_BLOCK_MAP_ENTRY FvBlocks[MAX_NUMBER_OF_FV_BLOCKS];
+ FFS_ATTRIBUTES FfsAttuibutes[MAX_NUMBER_OF_FILES_IN_FV];
+ EFI_FFS_FILE_HEADER2 FfsHeader[MAX_NUMBER_OF_FILES_IN_FV];
+ struct _FV_INFOMATION *FvNext;
+ ENCAP_INFO_DATA *EncapData;
+ UINT8 FvLevel;
+ CHAR8 *FvUiName;
+ UINT8 MulFvLevel;
+ CHAR8 AlignmentStr[16];
+ FFS_INFORMATION *ChildFvFFS;
+} FV_INFORMATION;
+
+typedef struct _FIRMWARE_DEVICE {
+ ///
+ /// Size of FD file
+ ///
+ UINT32 Size;
+ FV_INFORMATION *Fv;
+} FIRMWARE_DEVICE;
+
+typedef struct _FILENode {
+ CHAR8 *FileName;
+ UINT8 SubLevel;
+ struct _FILENode *Next;
+} FILENode;
+
+typedef struct {
+ CHAR8 *FvId;
+ FILENode *NewFile;
+ FILENode *OldFile;
+ FIRMWARE_DEVICE *FdData;
+ UINT8 FvLevel;
+ FV_INFORMATION *FvInFd;
+} Data;
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+);
+
+/**
+
+ TODO: Add function description
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN ENCAP_INFO_DATA **CurrentFvEncapData,
+ IN UINT32 *FfsCount,
+ IN OUT UINT8 *FvCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ );
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ );
+
+ /**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ );
+
+/**
+ Converts ASCII characters to Unicode.
+ Assumes that the Unicode characters are only these defined in the ASCII set.
+
+ String - Pointer to string that is written to FILE.
+ UniString - Pointer to unicode string
+
+ The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+ IN CHAR8 *String,
+ OUT CHAR16 *UniString
+ );
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+ );
+
+/**
+ Delete a file.
+
+ @param[in] FileName Name of the file need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibFmmtDeleteFile(
+ IN CHAR8 *FileName
+);
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibFmmtFreeFd (
+ FIRMWARE_DEVICE *Fd
+);
+
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ IN ENCAP_INFO_DATA *CurrentEncapData,
+ IN UINT32 Level_Break,
+ OUT FFS_INFORMATION **OutputFile
+);
+
+
+EFI_STATUS
+LibLocateFvViaFvId (
+ IN FIRMWARE_DEVICE *FdData,
+ IN CHAR8 *FvId,
+ IN OUT FV_INFORMATION **FvInFd
+);
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+);
+
+EFI_STATUS
+FvBufGetSize(
+IN VOID *Fv,
+OUT UINTN *Size
+);
+
+EFI_STATUS
+FvBufFindNextFile(
+IN VOID *Fv,
+IN OUT UINTN *Key,
+OUT VOID **File
+);
+#endif
diff --git a/BaseTools/Source/C/FMMT/FmmtConf.ini b/BaseTools/Source/C/FMMT/FmmtConf.ini
new file mode 100644
index 0000000000..36135116b3
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/FmmtConf.ini
@@ -0,0 +1,6 @@
+a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress
+ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress
+fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32
+d42ae6bd-1352-4bfb-909a-ca72a6eae889 LZMAF86 LzmaF86Compress
+3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress
+
diff --git a/BaseTools/Source/C/FMMT/GNUmakefile b/BaseTools/Source/C/FMMT/GNUmakefile
new file mode 100644
index 0000000000..81b99f25db
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/GNUmakefile
@@ -0,0 +1,16 @@
+## @file
+# GNU/Linux makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= ..
+
+APPNAME = FMMT
+
+LIBS = -lCommon
+
+OBJECTS = FmmtLib.o Rebase.o FirmwareModuleManagement.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
diff --git a/BaseTools/Source/C/FMMT/Makefile b/BaseTools/Source/C/FMMT/Makefile
new file mode 100644
index 0000000000..d6559d65fd
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/Makefile
@@ -0,0 +1,17 @@
+## @file
+# Windows makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+!INCLUDE ..\Makefiles\ms.common
+
+APPNAME = FMMT
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = FirmwareModuleManagement.obj FmmtLib.obj Rebase.obj
+
+!INCLUDE ..\Makefiles\ms.app
+
diff --git a/BaseTools/Source/C/FMMT/Rebase.h b/BaseTools/Source/C/FMMT/Rebase.h
new file mode 100644
index 0000000000..57604a357f
--- /dev/null
+++ b/BaseTools/Source/C/FMMT/Rebase.h
@@ -0,0 +1,31 @@
+/** @file Rebase.h
+
+ Library to rebase PE image.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FMMT_REBASE_H
+#define _FMMT_REBASE_H
+
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareFile.h>
+
+EFI_STATUS
+RebaseFfs(
+IN OUT UINT64 BaseAddress,
+IN CHAR8 *FileName,
+IN OUT EFI_FFS_FILE_HEADER *FfsFile,
+IN UINTN XipOffset
+);
+
+EFI_STATUS
+GetChildFvFromFfs (
+ IN UINT64 BaseAddress,
+ IN EFI_FFS_FILE_HEADER *FfsFile,
+ IN UINTN XipOffset
+);
+
+#endif
diff --git a/BaseTools/Source/C/GNUmakefile b/BaseTools/Source/C/GNUmakefile
index 990c6d0a82..b99b5121f5 100644
--- a/BaseTools/Source/C/GNUmakefile
+++ b/BaseTools/Source/C/GNUmakefile
@@ -47,6 +47,7 @@ VFRAUTOGEN = VfrCompile/VfrLexer.h
APPLICATIONS = \
BrotliCompress \
VfrCompile \
+ FMMT \
BfmLib \
EfiRom \
FCE \
diff --git a/BaseTools/Source/C/Makefile b/BaseTools/Source/C/Makefile
index 357e8b9003..4377ec5522 100644
--- a/BaseTools/Source/C/Makefile
+++ b/BaseTools/Source/C/Makefile
@@ -12,6 +12,7 @@ LIBRARIES = Common
APPLICATIONS = \
VfrCompile \
BrotliCompress \
+ FMMT \
BfmLib \
EfiRom \
FCE \
--
2.13.0.windows.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2019-07-01 11:28 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-07-01 11:27 [Patch v3 0/3] BaseTools: Move FCE & FMMT tools to edk2 repo Liming Gao
2019-07-01 11:27 ` [Patch v3 1/3] BaseTools: Add a tool BfmLib Liming Gao
2019-07-01 11:27 ` [Patch v3 2/3] BaseTools: Add a tool FCE Liming Gao
2019-07-01 11:27 ` [Patch v3 3/3] BaseTools: Add a tool FMMT Liming Gao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox