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.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.
+ 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/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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BINARY_CREATE_H_
+#define _BINARY_CREATE_H_ 1
+
+#include
+#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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//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.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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GNUC__
+#include "windows.h"
+#else
+#include
+#include
+#include
+#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/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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _BINARY_PARSE_H_
+#define _BINARY_PARSE_H_ 1
+
+#include
+#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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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.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.
+ 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 = "";
+ }
+ //
+ // 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 = "";
+ } 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 = "";
+ } 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/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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _COMMON_LIB_H_
+#define _COMMON_LIB_H_
+
+#include
+#include
+#include
+#ifdef __GNUC__
+#include
+#else
+#include
+#include
+#endif
+#include
+#include
+#include
+#include "CommonLib.h"
+#include
+
+#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/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.
+ 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.
+ 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 -o '.\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 -o '.\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 -o '.\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 file doesn't exist '%s'\n", FdName);
+ }
+ return EFI_ABORTED;
+ }
+ if ((Type == OUTFD) && (FdName == NULL) ) {
+ printf ("Error: The name is NULL.\n");
+ return EFI_ABORTED;
+ }
+ if ((Type == SETUPTXT) && (FdName == NULL) ) {
+ printf ("Error: The