* [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT
2019-06-21 1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
@ 2019-06-21 1:26 ` Zhang, Shenglei
2019-06-21 1:26 ` [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib Zhang, Shenglei
` (5 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21 1:26 UTC (permalink / raw)
To: devel; +Cc: Bob Feng, Liming Gao
FMMT is a tool to enable removal, addition and replacement of
FFS files in FD image binaries.
https://bugzilla.tianocore.org/show_bug.cgi?id=1847
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
.../Tools/FMMT/FirmwareModuleManagement.c | 2559 +++++++++
.../Tools/FMMT/FirmwareModuleManagement.h | 479 ++
Platform/Intel/Tools/FMMT/FmmtConf.ini | 6 +
Platform/Intel/Tools/FMMT/FmmtLib.c | 5051 +++++++++++++++++
Platform/Intel/Tools/FMMT/GNUmakefile | 16 +
Platform/Intel/Tools/FMMT/Makefile | 17 +
Platform/Intel/Tools/FMMT/Rebase.c | 846 +++
Platform/Intel/Tools/FMMT/Rebase.h | 31 +
8 files changed, 9005 insertions(+)
create mode 100644 Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
create mode 100644 Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
create mode 100644 Platform/Intel/Tools/FMMT/Makefile
create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
diff --git a/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
new file mode 100644
index 0000000000..63ae3c45a4
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
@@ -0,0 +1,2559 @@
+/** @file
+
+ FMMT main routine.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FirmwareModuleManagement.h"
+#include "Rebase.h"
+#include <stdlib.h>
+#include <wchar.h>
+
+CHAR8* mGuidToolDefinition = "FmmtConf.ini";
+extern EFI_FIRMWARE_VOLUME_HEADER *mFvHeader;
+extern UINT32 mFvLength;
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+#define EFI_FFS_VOLUME_TOP_FILE_GUID \
+{ \
+ 0x1BA0062E, 0xC779, 0x4582, { 0x85, 0x66, 0x33, 0x6A, 0xE8, 0xF7, 0x8F, 0x09 } \
+}
+#define FSP_FFS_INFORMATION_FILE_GUID \
+{ 0x912740be, 0x2284, 0x4734, { 0xb9, 0x71, 0x84, 0xb0, 0x27, 0x35, 0x3f, 0x0c }};
+
+static EFI_GUID mVTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
+static EFI_GUID mFSPGuid = FSP_FFS_INFORMATION_FILE_GUID;
+
+
+/**
+
+Routine Description:
+
+ The Usage of FMMT tool.
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+**/
+VOID
+Usage (
+ VOID
+ )
+{
+ //
+ // Summary usage
+ //
+ fprintf (stdout, "Usage: %s [options] \n\n", UTILITY_SHORT_NAME);
+
+ //
+ // Copyright declaration
+ //
+ fprintf (stdout, "Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.\n\n");
+
+ //
+ // Details Option
+ //
+ fprintf (stdout, "Options:\n");
+
+ //
+ // Command Line for View
+ //
+ fprintf (stdout, " -v <input-binary-file>\n\
+ View each FV and the named files within each FV.\n");
+
+ //
+ // Command Line for Delete entire FV
+ //
+ fprintf (stdout, " -d <input-binary-file> <FV-id> <output-binary-file>\n\
+ Delete the entire FV in an FD binary\n");
+
+ //
+ // Command Line for Delete file from FV
+ //
+ fprintf (stdout, " -d <input-binary-file> <FV-id> <File-Name> [<FV-id> <File-Name> ...] <output-binary-file>\n\
+ Delete a file (or files) from the firmware volume in an FD binary\n");
+
+ //
+ // Command Line for Add
+ //
+ fprintf (stdout, " -a <input-binary-file> <FV-id> <NewFilePath> [<FV-id> <NewFilePath> ...] <output-binary-file>\n\
+ Add a file (or files) to the firmware volume in an FD binary\n");
+
+ //
+ // Command Line for Replace
+ //
+ fprintf (stdout, " -r <input-binary-file> <FV-id> <File-Name> <NewFilePath> [<FV-id> <File-Name> <NewFilePath> ...] <output-binary-file>\n\
+ The replace command combines the functionality of remove and add into a single operation.\n");
+
+ fprintf (stdout, "\nNote:\n");
+ fprintf (stdout, " <FV-id> is the sequence of the firmware volume included in the FD image, it both support the sequentially format like FV0, FV1 and the FV's file guid value format.\n");
+ return;
+}
+
+
+BOOLEAN
+IsVtf(EFI_FFS_FILE_HEADER2* ffs) {
+ if (!memcmp(&ffs->Name, &mVTFGuid, sizeof (EFI_GUID))) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+BOOLEAN
+IsFsp(EFI_FFS_FILE_HEADER2* ffs) {
+ if (!memcmp(&ffs->Name, &mFSPGuid, sizeof (EFI_GUID))) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static
+EFI_STATUS
+GetBaseAddrFromVtf(FIRMWARE_DEVICE *FdData, CHAR8 *FvId, UINT64 *BaseAddr) {
+ EFI_STATUS Status;
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *FvInFd;
+
+ Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Get bottom FV
+ //
+ CurrentFv = FdData->Fv;
+ while (CurrentFv->FvNext) {
+ CurrentFv = CurrentFv->FvNext;
+ }
+ if (CurrentFv->FfsNumbers > 0 && IsVtf(&CurrentFv->FfsHeader[CurrentFv->FfsNumbers])) {
+ //
+ // Found VTF at the top of FV
+ // Assume 4G address
+ //
+ *BaseAddr = 0x100000000 - (FdData->Size - FvInFd->ImageAddress);
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+static
+EFI_STATUS
+GetBaseAddrFromFsp(FIRMWARE_DEVICE *FdData, CONST UINT8* FdBuffer, CHAR8 *FvId, UINT64 *BaseAddr)
+{
+ EFI_STATUS Status;
+ FV_INFORMATION *FvInFd;
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *FspFv;
+ UINT32 Offset;
+ UINT64 ImageSize;
+ UINT64 Size;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ BOOLEAN FspFound;
+
+ Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ ImageSize = 0;
+ Size = 0;
+ FspFound = FALSE;
+ FspFv = NULL;
+ CurrentFv = FdData->Fv;
+ while (CurrentFv) {
+ if (CurrentFv->FfsNumbers > 0 && IsFsp(&CurrentFv->FfsHeader[0])) {
+ Offset = CurrentFv->ImageAddress + CurrentFv->FfsAttuibutes[0].Offset;
+ CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
+ //
+ // Skip FFS header
+ //
+ Offset += GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)CurrentFile);
+ //
+ // Stip section header
+ //
+ Offset += GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)(FdBuffer + Offset));
+ //
+ // We have raw FSP here, and 24 is the image size
+ //
+ ImageSize = *((UINT32 *)(FdBuffer + Offset + 24));
+ //
+ // 28 is the base address
+ //
+ *BaseAddr = *((UINT32 *)(FdBuffer + Offset + 28));
+ FspFound = TRUE;
+ FspFv = CurrentFv;
+ }
+ if (CurrentFv == FvInFd){
+ break;
+ }
+ CurrentFv = CurrentFv->FvNext;
+ }
+ if (!FspFound) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Check if FSP binary contains this FV
+ //
+ while (FspFv != NULL) {
+ Size += FspFv->FvHeader->FvLength;
+ if (FspFv == FvInFd) {
+ break;
+ }
+ FspFv = FspFv->FvNext;
+ }
+ if (Size <= ImageSize) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+static
+VOID
+AddPadFile(EFI_FIRMWARE_VOLUME_HEADER *Fv, EFI_FFS_FILE_HEADER2 *PadFile, UINT32 PadFileSize) {
+ UINT32 hdrSize;
+
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset(PadFile, -1, PadFileSize);
+ }
+ else {
+ memset(PadFile, 0, PadFileSize);
+ }
+ PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
+ PadFile->Attributes = 0;
+
+ //
+ // Write pad file size (calculated size minus next file header size)
+ //
+ if (PadFileSize >= MAX_FFS_SIZE) {
+ memset(PadFile->Size, 0, sizeof(UINT8)* 3);
+ ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize;
+ PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
+ hdrSize = sizeof(EFI_FFS_FILE_HEADER2);
+ }
+ else {
+ PadFile->Size[0] = (UINT8)(PadFileSize & 0xFF);
+ PadFile->Size[1] = (UINT8)((PadFileSize >> 8) & 0xFF);
+ PadFile->Size[2] = (UINT8)((PadFileSize >> 16) & 0xFF);
+ hdrSize = sizeof(EFI_FFS_FILE_HEADER);
+ }
+
+ //
+ // Fill in checksums and state, they must be 0 for checksumming.
+ //
+ PadFile->IntegrityCheck.Checksum.Header = 0;
+ PadFile->IntegrityCheck.Checksum.File = 0;
+ PadFile->State = 0;
+ PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8((UINT8 *)PadFile, hdrSize);
+ PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
+
+ PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ PadFile->State = (UINT8)~(PadFile->State);
+ }
+}
+
+static
+UINT8* ReadFileToBuffer(CONST CHAR8 *FdName, UINT32 *FdSize) {
+ FILE* file;
+
+ UINT8 *FdBuffer = NULL;
+
+ file = fopen(FdName, "rb");
+ if (file == NULL)
+ return NULL;
+
+ fseek(file, 0, SEEK_SET);
+ fseek(file, 0, SEEK_END);
+ *FdSize = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ FdBuffer = malloc(*FdSize);
+ if (FdBuffer == NULL) {
+ goto FAIL;
+ }
+ if (fread(FdBuffer, 1, *FdSize, file) != *FdSize) {
+ goto FAIL;
+ }
+ fclose(file);
+ return FdBuffer;
+FAIL:
+ free(FdBuffer);
+ fclose(file);
+ return NULL;
+}
+
+static UINT32 CalcuFfsSize(EFI_FIRMWARE_VOLUME_HEADER* Fv, CONST EFI_FFS_FILE_HEADER2 *Ffs) {
+ EFI_FFS_FILE_HEADER2 *NextFile;
+ UINTN FfsSize;
+ UINTN FvSize;
+ UINTN Offset;
+
+ FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)Ffs);
+ FfsSize += (UINT8 *)ALIGN_POINTER(((UINT8 *)Ffs + FfsSize), 8) - ((UINT8 *)Ffs + FfsSize);
+ FvBufGetSize(Fv, &FvSize);
+ Offset = (UINT8 *)Ffs - (UINT8 *)Fv;
+ if (Offset + FfsSize < FvSize) {
+ NextFile = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)Ffs + FfsSize);
+ if (NextFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ FfsSize += GetFfsFileLength((EFI_FFS_FILE_HEADER *)NextFile);
+ }
+ }
+ return FfsSize;
+}
+
+static
+EFI_STATUS
+ReadFfsAlignment(
+IN EFI_FFS_FILE_HEADER *FfsFile,
+IN OUT UINT32 *Alignment
+)
+{
+ //
+ // Verify input parameters.
+ //
+ if (FfsFile == NULL || Alignment == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch ((FfsFile->Attributes >> 3) & 0x07) {
+
+ case 0:
+ //
+ // 1 byte alignment
+ //
+ *Alignment = 0;
+ break;
+
+ case 1:
+ //
+ // 16 byte alignment
+ //
+ *Alignment = 4;
+ break;
+
+ case 2:
+ //
+ // 128 byte alignment
+ //
+ *Alignment = 7;
+ break;
+
+ case 3:
+ //
+ // 512 byte alignment
+ //
+ *Alignment = 9;
+ break;
+
+ case 4:
+ //
+ // 1K byte alignment
+ //
+ *Alignment = 10;
+ break;
+
+ case 5:
+ //
+ // 4K byte alignment
+ //
+ *Alignment = 12;
+ break;
+
+ case 6:
+ //
+ // 32K byte alignment
+ //
+ *Alignment = 15;
+ break;
+
+ case 7:
+ //
+ // 64K byte alignment
+ //
+ *Alignment = 16;
+ break;
+
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+static
+BOOLEAN
+ReplaceFfs(EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, EFI_FFS_FILE_HEADER2 *OldFfs) {
+ UINT32 FfsSize;
+ UINT32 NewFileSize;
+ UINT32 Offset;
+ UINT32 Align;
+ UINT32 HdrSize;
+ UINT32 PadSize;
+ EFI_FFS_FILE_HEADER2 *Pad;
+
+ Align = 0;
+ PadSize = 0;
+ Pad = NULL;
+ ReadFfsAlignment((EFI_FFS_FILE_HEADER *)InputFfs, &Align);
+ Align = 1 << Align;
+ HdrSize = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+ FfsSize = CalcuFfsSize(Fv, OldFfs);
+ //
+ // Align data
+ //
+ if ((((UINT8 *)OldFfs - (UINT8 *)Fv) + HdrSize) % Align != 0) {
+ PadSize = ((UINT8 *)OldFfs - (UINT8 *)Fv) + sizeof (EFI_FFS_FILE_HEADER)+HdrSize;
+ while (PadSize % Align != 0) {
+ PadSize++;
+ }
+ PadSize -= HdrSize;
+ PadSize -= ((UINT8 *)OldFfs - (UINT8 *)Fv);
+ if (FfsSize < PadSize) {
+ return FALSE;
+ }
+ FfsSize -= PadSize;
+ Pad = OldFfs;
+ OldFfs = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + PadSize);
+ }
+
+ NewFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+ Offset = (UINT8 *)ALIGN_POINTER(((UINT8 *)OldFfs + NewFileSize), 8) - ((UINT8 *)OldFfs + NewFileSize);
+ if (FfsSize >= NewFileSize && FfsSize - NewFileSize <= 7) {
+ memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset((UINT8 *)OldFfs + NewFileSize, -1, FfsSize - NewFileSize);
+ }
+ else {
+ memset((UINT8 *)OldFfs + NewFileSize, 0, FfsSize - NewFileSize);
+ }
+ }
+ else if (FfsSize >= NewFileSize + sizeof(EFI_FFS_FILE_HEADER) + Offset) {
+ memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
+ AddPadFile(
+ Fv,
+ (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + NewFileSize + Offset),
+ FfsSize - NewFileSize - Offset
+ );
+ }
+ else {
+ return FALSE;
+ }
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ OldFfs->State = (UINT8)~(InputFfs->State);
+ }
+ if (PadSize != 0) {
+ AddPadFile(Fv, Pad, PadSize);
+ }
+ return TRUE;
+}
+
+static
+
+EFI_STATUS
+AddFfs(UINT8 *FdBuffer, UINT32 ImageAddress, EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, UINT32 *OffsetAdded) {
+ UINTN FreeOffset;
+ UINTN Offset;
+ UINTN FfsSize;
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ EFI_FFS_FILE_HEADER FreeHeader;
+
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset(&FreeHeader, -1, sizeof(EFI_FFS_FILE_HEADER));
+ }
+ else {
+ memset(&FreeHeader, 0, sizeof(EFI_FFS_FILE_HEADER));
+ }
+
+ FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+ Offset = 0;
+ CurrentFile = NULL;
+ FreeOffset = 0;
+ do {
+ if (FreeOffset == 0 && memcmp(FdBuffer + ImageAddress + (UINTN)ALIGN_POINTER(Offset, 8), &FreeHeader, sizeof(EFI_FFS_FILE_HEADER)) == 0) {
+ //
+ // Offset of free FV space found
+ //
+ FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8);
+ }
+ Status = FvBufFindNextFile(FdBuffer + ImageAddress, &Offset, (VOID **)&CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ break;
+ }
+ else if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (CurrentFile != NULL && CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD &&
+ ReplaceFfs(Fv, InputFfs, CurrentFile)) {
+ *OffsetAdded = (UINT8 *)CurrentFile - (FdBuffer + ImageAddress);
+ return EFI_SUCCESS;
+ }
+ } while (CurrentFile != NULL);
+
+ if (FreeOffset != 0) {
+ if (Fv->FvLength - FreeOffset < FfsSize) {
+ return EFI_ABORTED;
+ }
+ if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ InputFfs->State = (UINT8)~(InputFfs->State);
+ }
+ memcpy(FdBuffer + ImageAddress + FreeOffset, InputFfs, FfsSize);
+ *OffsetAdded = FreeOffset;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+static
+EFI_STATUS
+FindPreviousFile(VOID *Fv, VOID *CurrentFile, VOID **PreFile) {
+ EFI_STATUS Status;
+ VOID *File = NULL;
+ UINTN Offset = 0;
+
+ do {
+ *PreFile = File;
+ Status = FvBufFindNextFile(Fv, &Offset, &File);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ break;
+ }
+ else if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ if (File == CurrentFile) {
+ return EFI_SUCCESS;
+ }
+ } while (CurrentFile != NULL);
+ *PreFile = NULL;
+ return Status;
+}
+
+static
+BOOLEAN
+NeedNewPath(FV_INFORMATION *FvInFd, CHAR8 *FvId, UINT32 FileIndex, BOOLEAN IsAdd) {
+ UINT32 Index;
+
+ Index = 0;
+
+ if (strcmp(FvId, FvInFd->FvName) != 0) {
+ return FALSE;
+ }
+ if (IsAdd) {
+ return TRUE;
+ }
+ if (FvInFd->FfsAttuibutes[FileIndex].FvLevel != 1) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ if (FvInFd->FfsAttuibutes[Index].FvLevel != 1) {
+ continue;
+ }
+ switch (FvInFd->FfsHeader[Index].Type) {
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static UINT32 FindFile(FV_INFORMATION *FvInFd, UINT8 FvLevel, CHAR8 *File, UINT32 *MatchIndex) {
+ UINT32 Index = 0;
+ CHAR16 *UIName;
+ CHAR16 *FfsUIName;
+ UINT32 FileNumber = 0;
+
+ UIName = (CHAR16 *)malloc(_MAX_PATH);
+ if (NULL == UIName) {
+ return 0;
+ }
+ FfsUIName = (CHAR16 *)malloc(_MAX_PATH);
+ if (NULL == FfsUIName) {
+ free(UIName);
+ return 0;
+ }
+ LibAscii2Unicode(File, UIName);
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ //
+ // Compare the New File Name with UI Name of FFS
+ // NOTE: The UI Name is Unicode, but the New File Name is Ascii.
+ //
+ memcpy(FfsUIName, (CHAR16 *)(FvInFd->FfsAttuibutes[Index].UiName), _MAX_PATH);
+
+ if (FvInFd->FfsAttuibutes[Index].UiNameSize > 0 && memcmp(UIName, FfsUIName, FvInFd->FfsAttuibutes[Index].UiNameSize) == 0) {
+ FileNumber += 1;
+ *MatchIndex = Index;
+ if (FileNumber > 1) {
+ break;
+ }
+ }
+
+ }
+ free(UIName);
+ free(FfsUIName);
+
+ return FileNumber;
+}
+
+/**
+ Search the config file from the path list.
+
+ Split the path from env PATH, and then search the cofig
+ file from these paths. The priority is from left to
+ right of PATH string. When met the first Config file, it
+ will break and return the pointer to the full file name.
+
+ @param PathList the pointer to the path list.
+ @param FileName the pointer to the file name.
+
+ @retval The pointer to the file name.
+ @return NULL An error occurred.
+**/
+CHAR8 *
+SearchConfigFromPathList (
+ IN CHAR8 *PathList,
+ IN CHAR8 *FileName
+)
+{
+ CHAR8 *CurDir;
+ CHAR8 *FileNamePath;
+
+ CurDir = NULL;
+ FileNamePath = NULL;
+
+#ifndef __GNUC__
+ CurDir = strtok (PathList,";");
+#else
+ CurDir = strtok (PathList,":");
+#endif
+ while (CurDir != NULL) {
+ FileNamePath = (char *)calloc(
+ strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
+ sizeof(char)
+ );
+ if (FileNamePath == NULL) {
+ return NULL;
+ }
+ sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
+ if (access (FileNamePath, 0) != -1) {
+ return FileNamePath;
+ }
+#ifndef __GNUC__
+ CurDir = strtok(NULL, ";");
+#else
+ CurDir = strtok(NULL, ":");
+#endif
+ free (FileNamePath);
+ FileNamePath = NULL;
+ }
+ return NULL;
+}
+
+UINT32 lenList(FILENode* head){
+ FILENode *p = head;
+ UINT32 sum=0;
+ if(head==NULL) return 0;
+ while(p!=NULL){
+ sum+=1;
+ p=p->Next;
+ }
+ return sum;
+}
+
+void sortList(FILENode* head){
+ UINT32 len = lenList(head);
+ FILENode *p = head;
+ UINT32 i;
+ UINT32 j;
+ if(len==0) return;
+ for(i=1; i<len; ++i){
+ p = head;
+ for(j=0; j<len-i; j++){
+ if(p->SubLevel < p->Next->SubLevel){
+ CHAR8 *FileName = p->FileName;
+ UINT8 tmp = p->SubLevel;
+ p->SubLevel = p->Next->SubLevel;
+ p->Next->SubLevel = tmp;
+ p->FileName = p->Next->FileName;
+ p->Next->FileName = FileName;
+ }
+ p=p->Next;
+ }
+ }
+}
+
+BOOLEAN
+ParseSection (
+ IN EFI_FFS_FILE_HEADER2 *InputFfs
+)
+{
+ BOOLEAN UISectionFlag;
+ UINT32 SectionLength;
+ UINT32 ParsedLength;
+ UINT32 FfsFileSize;
+ UINT8 *Ptr;
+ EFI_SECTION_TYPE Type;
+
+ UISectionFlag = FALSE;
+ Ptr = NULL;
+ SectionLength = 0;
+ ParsedLength = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
+ FfsFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
+
+ while (ParsedLength < FfsFileSize) {
+ Ptr = (UINT8 *)InputFfs + ParsedLength;
+ SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if ((SectionLength == 0xffffff) && (Type == 0xff)) {
+ ParsedLength += 4;
+ continue;
+ }
+ if (Type == EFI_SECTION_USER_INTERFACE) {
+ UISectionFlag = TRUE;
+ break;
+ }
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+ return UISectionFlag;
+
+}
+
+
+/**
+
+ Show the FD image layout information. Only display the modules with UI name.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FvName The FV ID in the FD file;
+ @param[in] ViewFlag Is this call for view or other operate(add/del/replace)
+ @param[in] FdData The Fd data structure store the FD information.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageView (
+ IN CHAR8* FdInName,
+ IN CHAR8* FvName,
+ IN BOOLEAN ViewFlag,
+ IN FIRMWARE_DEVICE **FdData
+)
+{
+ EFI_STATUS Status;
+ EFI_STATUS ErrorStatus;
+ FIRMWARE_DEVICE *LocalFdData;
+ FV_INFORMATION *CurrentFv;
+ FILE *InputFile;
+ UINT32 FvSize;
+ UINTN BytesRead;
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage;
+ UINT32 FfsCount;
+ UINT8 FvCount;
+ CHAR8 *TemDir;
+
+ LocalFdData = NULL;
+ CurrentFv = NULL;
+ FvImage = NULL;
+ TemDir = NULL;
+ FvSize = 0;
+ BytesRead = 0;
+ FfsCount = 0;
+ FvCount = 0;
+ ErrorStatus = EFI_SUCCESS;
+
+ //
+ // Check the FD file name/path.
+ //
+ if (FdInName == NULL) {
+ Error("FMMT", 0, 1001, "Invalid parameter! Please specify <input-binary-file>", FdInName);
+ Usage();
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open the file containing the FV
+ //
+ InputFile = fopen (FdInName, "rb");
+ if (InputFile == NULL) {
+ Error (NULL, 0, 0001, "Error opening the input file", FdInName);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = LibFindFvInFd (InputFile, &LocalFdData);
+
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 1001, "Error while search FV in FD", "");
+ fclose (InputFile);
+ return EFI_ABORTED;
+ }
+
+ CurrentFv = LocalFdData->Fv;
+
+
+ do {
+
+ memset (CurrentFv->FvName, '\0', _MAX_PATH);
+
+ if (FvCount == 0) {
+ sprintf (CurrentFv->FvName, "FV%d", FvCount);
+ } else {
+ sprintf (CurrentFv->FvName, "FV%d", FvCount);
+ }
+
+ //
+ // Determine size of FV
+ //
+ if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
+ Error (NULL, 0, 0003, "error parsing FV image", "%s FD file is invalid", InputFile);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ Status = LibGetFvSize(InputFile, &FvSize);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", InputFile);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET);
+
+
+ FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize);
+
+ if (FvImage == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ BytesRead = fread (FvImage, 1, FvSize, InputFile);
+ if ((unsigned int) BytesRead != FvSize) {
+ Error ("FMMT", 0, 0004, "error reading FvImage from", FdInName);
+ free (FvImage);
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+
+ //
+ // Collect FV information each by each.
+ //
+ Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &CurrentFv->EncapData, &FfsCount, &FvCount, ViewFlag, FALSE);
+ if (FvImage != NULL) {
+ free (FvImage);
+ FvImage = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while get information from FV %s", FvName);
+ ErrorStatus = Status;
+ //
+ // If the FV to be parsed error is the same with the input FV in add, replace and delete
+ // operation, abort the program directly.
+ //
+ if ((FvName != NULL) && ((CurrentFv->FvName) != NULL) && !strcmp(CurrentFv->FvName, FvName)) {
+ fclose (InputFile);
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+ }
+
+
+ FfsCount = 0;
+
+ CurrentFv = CurrentFv->FvNext;
+
+ } while (CurrentFv != NULL);
+
+ fclose (InputFile);
+
+ if (ViewFlag) {
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ ErrorStatus = EFI_ABORTED;
+ goto Done;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ Status = LibRmDir (TemDir);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ ErrorStatus = Status;
+ }
+ }
+Done:
+ if (!ViewFlag) {
+ *FdData = LocalFdData;
+ } else {
+ LibFmmtFreeFd( LocalFdData);
+ }
+ return ErrorStatus;
+}
+
+/**
+ Add FFS file into a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FileList The FV ID and FFS file Data;
+ @param[in] count The length of FileList;
+ @param[in] FdOutName Name of output FD binary/image file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageAdd(
+ IN CHAR8* FdInName,
+ IN Data *FileList,
+ IN int count,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT8 FvNumInFd;
+ UINT8 FvNumInFdCounter;
+ UINT8 NewAddedFfsLevel;
+ FFS_INFORMATION *OutputFileName;
+ UINT32 Index;
+ UINT32 EndId;
+ UINT8 *FdBuffer;
+ EFI_FIRMWARE_VOLUME_HEADER *Fv;
+ UINT32 FdSize;
+ EFI_FFS_FILE_HEADER2 *InputFfs;
+ UINT32 NewFileSize;
+ UINT64 BaseAddr;
+ UINT32 OffsetAdded;
+ int i;
+ int j;
+ Data *tmp;
+ CHAR8* FvId;
+ CHAR8* NewFile;
+ FILENode *NewFileNode;
+ BOOLEAN HasUISection;
+ HasUISection = FALSE;
+ Index = 0;
+ EndId = 0;
+ NewFvLength = 0;
+ FvNumInFd = 0;
+ FvNumInFdCounter = 0;
+ NewAddedFfsLevel = 0;
+ FdData = NULL;
+ FvInFd = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ OutputFileName = NULL;
+ FvId = NULL;
+ NewFile = NULL;
+
+ FdBuffer = NULL;
+ InputFfs = NULL;
+ BaseAddr = 0;
+ OffsetAdded = 0;
+ FdSize = 0;
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ FdData = tmp->FdData;
+ if (FdData == NULL) {
+ Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
+ if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+ return Status;
+ }
+ if (FdData == NULL) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
+ return EFI_ABORTED;
+ }
+
+ Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
+ return Status;
+ }
+ (FileList + i) -> FdData = FdData;
+ (FileList + i) -> FvInFd = FvInFd;
+ (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ for (j = i + 1; j < count; j++){
+ if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+ continue;
+ }
+ if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+ NewFileNode = (FileList + j)->NewFile;
+ while (NewFileNode ->Next != NULL) {
+ NewFileNode = NewFileNode->Next;
+ }
+ NewFileNode->Next = (FileList + i)->NewFile;
+ (FileList + i)->FvId = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ if ((FileList + i)->FvId == NULL) {
+ continue;
+ }
+ sortList ((FileList + i)-> NewFile);
+ }
+
+ TemDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ if (FdBuffer == NULL) {
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+ return EFI_ABORTED;
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ if (FvId == NULL) {
+ continue;
+ }
+ FdData = tmp->FdData;
+ FvInFd = tmp->FvInFd;
+ NewFileNode =tmp->NewFile;
+
+ NewFile = NewFileNode->FileName;
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ HasUISection = FALSE;
+ HasUISection = ParseSection(InputFfs);
+ if (!HasUISection) {
+ printf ("WARNING: The newly add file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
+ }
+ if (NeedNewPath(FvInFd, FvId, 0, TRUE)) {
+ do {
+ NewFile = NewFileNode->FileName;
+ //
+ // TODO: currently only root FV is handled
+ //
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
+
+ Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0003, "error while adding file", "Not enough space to add FFS");
+ goto FAILED;
+ }
+ //
+ // Calculate base address of Current FV
+ //
+ if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ else {
+ Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ }
+ }
+ NewFileNode = NewFileNode->Next;
+ free (InputFfs);
+ InputFfs = NULL;
+ } while (NewFileNode != NULL);
+ } else {
+ do {
+ NewFile = NewFileNode->FileName;
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ Error ("FMMT", 0, 2000, "error while adding file", "New file name is too long!");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2));
+ if (FvInFd->FfsNumbers == 0) {
+ NewAddedFfsLevel = FvInFd->FfsAttuibutes[0].Level;
+ }
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ if (FvInFd->FfsAttuibutes[Index].IsFvStart == 1) {
+ FvNumInFdCounter++;
+ }
+ if ( FvNumInFdCounter == FvNumInFd && FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
+ NewAddedFfsLevel = FvInFd->FfsAttuibutes[Index].Level;
+ EndId = Index+1;
+ break;
+ }
+ if (FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
+ FvNumInFdCounter--;
+ if (FvNumInFdCounter == 0) {
+ FvNumInFd--;
+ }
+ }
+ }
+
+ //
+ // Add the new file into FV.
+ //
+ FvInFd->FfsNumbers += 1;
+ for (Index = FvInFd->FfsNumbers; Index > EndId; Index--) {
+ FvInFd->FfsAttuibutes[Index] = FvInFd->FfsAttuibutes[Index - 1];
+ }
+ strncpy(FvInFd->FfsAttuibutes[EndId].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[EndId].FfsName[_MAX_PATH - 1] = 0;
+ FvInFd->FfsAttuibutes[EndId].Level = NewAddedFfsLevel;
+ memset (&FvInFd->FfsAttuibutes[EndId].GuidName, '\0', sizeof(EFI_GUID));
+ if (EndId > 0) {
+ FvInFd->FfsAttuibutes[EndId].FvLevel = FvInFd->FfsAttuibutes[EndId - 1].FvLevel;
+ FvInFd->FfsAttuibutes[EndId - 1].IsFvEnd = 0;
+ }
+ FvInFd->FfsAttuibutes[EndId].IsFvEnd = 1;
+ FvInFd->FfsAttuibutes[EndId].IsFvStart = 0;
+ NewFileNode = NewFileNode->Next;
+ } while (NewFileNode != NULL);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+ goto FAILED;
+ }
+
+ NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+ if (NewFvFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+ fseek(NewFvFile,0,SEEK_SET);
+ Buffer = malloc ((size_t)NewFvLength);
+ if (Buffer == NULL) {
+ Status = EFI_ABORTED;
+ fclose(NewFvFile);
+ goto FAILED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+ free (Buffer);
+ Status = EFI_ABORTED;
+ fclose(NewFvFile);
+ goto FAILED;
+ }
+
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+ } else {
+ Error ("FMMT", 0, 0004, "error writing FD file", "The add ffs file is too large.");
+ }
+ fclose(NewFvFile);
+ free(Buffer);
+ }
+ }
+
+ Status = LibRmDir(TemDir);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ goto FAILED;
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+ free(FdBuffer);
+ free(InputFfs);
+ printf ("Create New FD file successfully. \n\nDone! \n");
+ return EFI_SUCCESS;
+
+ FAILED:
+ if (FdBuffer != NULL) {
+ free(FdBuffer);
+ }
+ if (InputFfs != NULL) {
+ free(InputFfs);
+ }
+ return Status;
+}
+
+/**
+Delete a root FV from FD.
+
+@param[in] FdInName Input FD binary/image file name;
+@param[in] FvName FV name;
+@param[in] FdOutName Name of output fd file.
+
+@retval EFI_SUCCESS
+@retval EFI_INVALID_PARAMETER
+@retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageDeleteFv(
+ IN CHAR8* FdInName,
+ IN CHAR8* FvName,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FV_INFORMATION *FvInFd;
+ FILE *NewFdFile;
+ CHAR8 *TemDir;
+
+ UINT8 *FdBuffer = NULL;
+ UINT8 *FdBak = NULL;
+ UINT32 FdSize = 0;
+
+ FIRMWARE_DEVICE *FdData = NULL;
+
+ TemDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ Status = FmmtImageView(FdInName, NULL, FALSE, &FdData);
+ if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+ goto END;
+ }
+ if (FdData == NULL) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+
+ FvInFd = FdData->Fv;
+ while (FvInFd) {
+ if (FvInFd->FvUiName && strcmp(FvInFd->FvUiName, FvName) == 0) {
+ break;
+ }
+ FvInFd = FvInFd->FvNext;
+ }
+ if (!FvInFd) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot find this FV!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ FdBak = FdBuffer;
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot read FD file!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+
+ if (FvInFd->ImageAddress == 0) {
+ FdBuffer = FdBuffer + FvInFd->FvHeader->FvLength;
+ FdSize -= (UINT32)FvInFd->FvHeader->FvLength;
+ } else {
+ if (FvInFd->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ memset(FdBuffer + FvInFd->ImageAddress, -1, (size_t)FvInFd->FvHeader->FvLength);
+ }
+ else {
+ memset(FdBuffer + FvInFd->ImageAddress, 0, (size_t)FvInFd->FvHeader->FvLength);
+ }
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+
+ Status = LibRmDir(TemDir);
+
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while deleting root FV", "remove directory failed!");
+ goto END;
+ }
+
+ printf("Create New FD file successfully. \n\nDone! \n");
+END:
+ LibFmmtFreeFd(FdData);
+ free(FdBak);
+ return Status;
+}
+
+/**
+ Delete an FFS file from a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FileList The FV ID and FFS file Data;
+ @param[in] count The length of FileList;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageDelete (
+ IN CHAR8* FdInName,
+ IN Data *FileList,
+ IN int count,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ UINT32 Index;
+ UINT32 FfsFoundFlag;
+ FFS_INFORMATION *OutputFileName;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT8 FvNumInFd;
+ UINT32 Offset;
+ UINT8 *FdBuffer;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ EFI_FFS_FILE_HEADER2 *PreFile;
+ Data *tmp;
+ CHAR8* FvId;
+ CHAR8* DelFile;
+ FILENode *OldFileNode;
+ int i;
+ UINT32 FfsSize;
+ UINT32 FdSize;
+ int j;
+
+ FdSize = 0;
+ Index = 0;
+ NewFvLength = 0;
+ FfsFoundFlag = 0;
+ FdData = NULL;
+ FvInFd = NULL;
+ OutputFileName = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ FvNumInFd = 0;
+ Offset = 0;
+ FdBuffer = NULL;
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ FdData = tmp->FdData;
+ if (FdData == NULL) {
+ Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
+ if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
+ return Status;
+ }
+ if (FdData == NULL) {
+ Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
+ return EFI_ABORTED;
+ }
+
+ Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
+ return Status;
+ }
+ (FileList + i) -> FdData = FdData;
+ (FileList + i) -> FvInFd = FvInFd;
+ (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+ }
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp-> OldFile;
+ do {
+ DelFile = OldFileNode->FileName;
+ if (FvInFd == NULL) {
+ break;
+ }
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+ if (FfsFoundFlag) {
+ if (FfsFoundFlag > 1) {
+ printf("Duplicated file found in this FV, file name: %s\n", DelFile);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
+ return EFI_ABORTED;
+ }
+ OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+ OldFileNode = OldFileNode->Next;
+ } while (OldFileNode != NULL);
+ }
+
+ for (i = 0; i < count; i++) {
+ for (j = i + 1; j < count; j++)
+ {
+ if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+ continue;
+ }
+ if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+ OldFileNode = (FileList + j)->OldFile;
+ while (OldFileNode ->Next != NULL) {
+ OldFileNode = OldFileNode->Next;
+ }
+ OldFileNode->Next = (FileList + i)->OldFile;
+ (FileList + i)->FvId = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ if ((FileList + i)->FvId == NULL) {
+ continue;
+ }
+ sortList ((FileList + i)-> OldFile);
+ }
+
+ TemDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ if (FdBuffer == NULL) {
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while deleting file", "cannot read input file.");
+ return EFI_ABORTED;
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ if (FvId == NULL) {
+ continue;
+ }
+ FdData = tmp->FdData;
+ FvInFd = tmp->FvInFd;
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp->OldFile;
+ DelFile = OldFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+ if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
+ do {
+ DelFile = OldFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+ //
+ // TODO: currently only root FV is handled
+ //
+ Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
+ if (FdBuffer != NULL) {
+ CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
+
+ FfsSize = CalcuFfsSize((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile);
+
+ FindPreviousFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, (VOID **) &PreFile);
+ if (PreFile != NULL && PreFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ FfsSize += (UINT8 *)CurrentFile - (UINT8 *)PreFile;
+ CurrentFile = PreFile;
+ }
+ AddPadFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, FfsSize);
+ }
+ OldFileNode = OldFileNode -> Next;
+ } while (OldFileNode != NULL);
+ } else {
+ do {
+ DelFile = OldFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
+
+ if (FfsFoundFlag) {
+ //
+ // Delete this FFS file from Current FV structure.
+ //
+ Status = LibFmmtDeleteFile (FvInFd->FfsAttuibutes[Index].FfsName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+ Error ("FMMT", 0, 0004, "Cannot find the file need to delete", "Please check the name of the file you want to delete!");
+ goto FAILED;
+ }
+
+ memset(FvInFd->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+ FvInFd->FfsAttuibutes[Index].Level = 0xFF;
+
+ //
+ // Since we can avoid to add NULL ffs file, at this time we don't need to decrease the FFS number.
+ // If decrease operation executed, we should adjust the ffs list. It will bring in more complex.
+ //
+ //FvInFd->FfsNumbers -= 1;
+ memset(FvInFd->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+ if (FvInFd->FfsAttuibutes[Index].FvLevel > 1) {
+ for (j = Index - 1; j >= 0; j--) {
+ if (FvInFd->FfsAttuibutes[j].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel - 1) {
+ break;
+ }
+ }
+ if (Index+1 <= FvInFd->FfsNumbers) {
+ if (FvInFd->FfsAttuibutes[Index+1].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel + 1) {
+ for (j = Index+1; j <= (signed)FvInFd->FfsNumbers; j++) {
+ if (FvInFd->FfsAttuibutes[j].FvLevel > FvInFd->FfsAttuibutes[Index].FvLevel) {
+ Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[j].FfsName);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+ return Status;
+ }
+ memset(FvInFd->FfsAttuibutes[j].FfsName, '\0', _MAX_PATH);
+ FvInFd->FfsAttuibutes[j].Level = 0xFF;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ OldFileNode = OldFileNode -> Next;
+
+ }while (OldFileNode != NULL);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+ goto FAILED;
+ }
+
+ NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+ if (NewFvFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+ fseek(NewFvFile,0,SEEK_SET);
+ Buffer = malloc ((size_t)NewFvLength);
+ if (Buffer == NULL) {
+ fclose(NewFvFile);
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+ fclose(NewFvFile);
+ free(Buffer);
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+ memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+ free(Buffer);
+ fclose(NewFvFile);
+ }
+ }
+
+ Status = LibRmDir(TemDir);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ goto FAILED;
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto FAILED;
+ }
+
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+ free(FdBuffer);
+ printf("Create New FD file successfully. \n\nDone! \n");
+ return EFI_SUCCESS;
+
+ FAILED:
+ free(FdBuffer);
+ return Status;
+}
+
+/**
+ Replace the exist FFS file with new one from a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FileList The FV ID and FFS file Data;
+ @param[in] count The length of FileList;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+FmmtImageReplace (
+ IN CHAR8* FdInName,
+ IN Data *FileList,
+ IN int count,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ UINT32 Index;
+ UINT32 FfsFoundFlag;
+ FFS_INFORMATION *OutputFileName;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT32 Offset;
+ UINT8 *FdBuffer;
+ UINT8 FvNumInFd;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ EFI_FIRMWARE_VOLUME_HEADER *Fv;
+ UINT32 FdSize;
+ EFI_FFS_FILE_HEADER2 *InputFfs;
+ UINT32 NewFileSize;
+ UINT32 PadFileSize;
+ UINT64 BaseAddr;
+ UINT32 OffsetAdded;
+ Data *tmp;
+ CHAR8* FvId;
+ CHAR8* OldFile;
+ CHAR8* NewFile;
+ int i;
+ int j;
+ FILENode *OldFileNode;
+ FILENode *NewFileNode;
+ BOOLEAN HasUISection;
+ HasUISection = FALSE;
+ Index = 0;
+ NewFvLength = 0;
+ FfsFoundFlag = 0;
+ FdData = NULL;
+ FvInFd = NULL;
+ OutputFileName = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ Offset = 0;
+ FdBuffer = NULL;
+ InputFfs = NULL;
+ BaseAddr = 0;
+ OffsetAdded = 0;
+ FdSize = 0;
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ FdData = tmp->FdData;
+ if (FdData == NULL){
+ Status = FmmtImageView(FdInName, FvId, FALSE, &FdData);
+ if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ return Status;
+ }
+
+ if (FdData == NULL) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "");
+ return EFI_ABORTED;
+ }
+
+ Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0005, "error while locate FV in FD", "");
+ return Status;
+ }
+ (FileList + i) -> FdData = FdData;
+ (FileList + i) -> FvInFd = FvInFd;
+ (FileList + i) -> FvLevel = FvInFd -> FvLevel;
+ }
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp-> OldFile;
+ NewFileNode = tmp-> NewFile;
+ do {
+ OldFile = OldFileNode -> FileName;
+ NewFile = NewFileNode -> FileName;
+ if (FvInFd == NULL) {
+ break;
+ }
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+
+ if (FfsFoundFlag) {
+ if (FfsFoundFlag > 1) {
+ printf("Duplicated file found in this FV, file name: %s\n", OldFile);
+ return EFI_ABORTED;
+ }
+ //
+ // Replace this FFS file with the new one.
+ // strcpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile);
+ } else {
+ printf ("Could not found the FFS file need to be replaced from FD! file name: %s\n", OldFile);
+ return EFI_ABORTED;
+ }
+ OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+ NewFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
+ OldFileNode = OldFileNode->Next;
+ NewFileNode = NewFileNode->Next;
+ } while (OldFileNode != NULL && NewFileNode != NULL);
+ }
+
+ for (i = 0; i < count; i++) {
+ for (j = i + 1; j < count; j++)
+ {
+ if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
+ continue;
+ }
+ if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
+ OldFileNode = (FileList + j)->OldFile;
+ NewFileNode = (FileList + j)->NewFile;
+ while (OldFileNode->Next != NULL && NewFileNode->Next != NULL) {
+ OldFileNode = OldFileNode->Next;
+ NewFileNode = NewFileNode->Next;
+ }
+ OldFileNode->Next = (FileList + i)->OldFile;
+ NewFileNode->Next = (FileList + i)->NewFile;
+ (FileList + i)->FvId = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ if ((FileList + i)->FvId == NULL) {
+ continue;
+ }
+ sortList ((FileList + i)-> OldFile);
+ sortList ((FileList + i)-> NewFile);
+ }
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ if (FdBuffer == NULL) {
+ FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
+ if (FdBuffer == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+ return EFI_ABORTED;
+ }
+ }
+
+ for (i = 0; i < count; i ++){
+ tmp = FileList + i;
+ FvId = tmp->FvId;
+ if (FvId == NULL) {
+ continue;
+ }
+ FdData = tmp->FdData;
+ FvInFd = tmp->FvInFd;
+ FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
+ OldFileNode = tmp-> OldFile;
+ OldFile = OldFileNode -> FileName;
+ NewFileNode = tmp-> NewFile;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+
+ NewFile = NewFileNode->FileName;
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+ HasUISection = FALSE;
+ HasUISection = ParseSection(InputFfs);
+ if (!HasUISection) {
+ printf ("WARNING: The newly replace file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
+ }
+ if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
+ do {
+ OldFile = OldFileNode -> FileName;
+ NewFile = NewFileNode -> FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+ //
+ // TODO: currently only root FV is handled
+ //
+ InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
+ if (InputFfs == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
+ Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
+ OffsetAdded = FvInFd->FfsAttuibutes[Index].Offset;
+
+ if (!ReplaceFfs(Fv, InputFfs, (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset))) {
+ Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0003, "error while replacing file", "cannot add ffs");
+ goto END;
+ }
+ //
+ // Set original FFS to PAD file
+ //
+ CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset);
+ PadFileSize = CalcuFfsSize(Fv, CurrentFile);
+ AddPadFile(Fv, CurrentFile, PadFileSize);
+ }
+
+ //
+ // Calculate base address of Current FV
+ //
+ if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ else {
+ Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
+ if (!EFI_ERROR(Status)) {
+ mFvHeader = FvInFd->FvHeader;
+ mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
+ RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
+ }
+ }
+ }
+ OldFileNode = OldFileNode -> Next;
+ NewFileNode = NewFileNode -> Next;
+ free (InputFfs);
+ InputFfs = NULL;
+ } while (OldFileNode != NULL && NewFileNode!= NULL);
+ } else {
+ do {
+ OldFile = OldFileNode->FileName;
+ NewFile = NewFileNode->FileName;
+ FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
+ //
+ // Replace this FFS file with the new one.
+ //
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ Error ("FMMT", 0, 2000, "error while replacing file", "New file name is too long!");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+ strncpy(FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
+ OldFileNode = OldFileNode->Next;
+ NewFileNode = NewFileNode->Next;
+ } while (OldFileNode != NULL && NewFileNode != NULL);
+ Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
+ free (FdBuffer);
+ return Status;
+ }
+
+ NewFvFile = fopen (OutputFileName->FFSName, "rb+");
+ if (NewFvFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+ fseek(NewFvFile,0,SEEK_SET);
+ Buffer = malloc ((size_t)NewFvLength);
+ if (Buffer == NULL) {
+ fclose(NewFvFile);
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
+ free(Buffer);
+ free (FdBuffer);
+ fclose(NewFvFile);
+ return EFI_ABORTED;
+ }
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
+ }else {
+ Error ("FMMT", 0, 0004, "error writing FD file", "The replace ffs file is too large.");
+ }
+ free(Buffer);
+ fclose(NewFvFile);
+ }
+ }
+
+ Status = LibRmDir(TemDir);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
+ }
+
+ NewFdFile = fopen(FdOutName, "wb");
+ if (NewFdFile == NULL) {
+ Error("FMMT", 0, 0004, "error while replacing file", "Cannot open target FD file!");
+ Status = EFI_ABORTED;
+ goto END;
+ }
+ fwrite(FdBuffer, 1, FdSize, NewFdFile);
+ fclose(NewFdFile);
+ free(FdBuffer);
+ printf("Create New FD file successfully. \n\nDone! \n");
+ return EFI_SUCCESS;
+
+ END:
+ if (FdBuffer != NULL) {
+ free(FdBuffer);
+ }
+ if (InputFfs != NULL) {
+ free(InputFfs);
+ }
+ return EFI_ABORTED;
+}
+
+/**
+
+The main entry of FMMT.
+
+@param argc The number of input parameters.
+@param *argv[] The array pointer to the parameters.
+
+@retval 0 The application exited normally.
+@retval 1 An error occurred.
+
+**/
+int main(
+ int Argc,
+ char *Argv[]
+)
+{
+ EFI_STATUS Status;
+ CHAR8 *TemDir;
+ FILE *CheckFileExist;
+ CHAR8 *InFilePath;
+ CHAR8 FullGuidToolDefinition[_MAX_PATH];
+ CHAR8 *FileName;
+ UINTN FileNameIndex;
+ CHAR8 *PathList;
+ UINTN EnvLen;
+ CHAR8 *NewPathList;
+ Data *FileData;
+ int index;
+ int count;
+ int exist;
+ int j;
+ FILENode *p;
+ FILENode *q;
+
+ p = NULL;
+ q = NULL;
+ TemDir = NULL;
+ CheckFileExist = NULL;
+ PathList = NULL;
+ NewPathList = NULL;
+ EnvLen = 0;
+ count = 0;
+ exist = -1;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return 1;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ //
+ // Print utility header
+ //
+ printf ("Intel(R) %s. Version %d.%d, %s. %s.\n",
+ UTILITY_NAME,
+ UTILITY_MAJOR_VERSION,
+ UTILITY_MINOR_VERSION,
+ __DATE__,
+ __BUILD_VERSION
+ );
+
+ //
+ // Should have more than 1 arguments.
+ //
+ if (Argc <= 1) {
+ Usage();
+ return 1;
+ }
+
+ //
+ // Workaroud: the first call to this function
+ // returns a file name ends with dot
+ //
+#ifndef __GNUC__
+ tmpnam (NULL);
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ close(Fdtmp);
+#endif
+
+ //
+ // Save, skip filename arg
+ //
+ FileName = Argv[0];
+ Argc--;
+ Argv++;
+
+ //
+ // Get the same path with the application itself
+ //
+ if (strlen (FileName) > _MAX_PATH - 1) {
+ Error ("FMMT", 0, 2000, "Parameter: The input filename is too long", NULL);
+ return 1;
+ }
+ strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1);
+ FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+ FileNameIndex = strlen (FullGuidToolDefinition);
+ while (FileNameIndex != 0) {
+ FileNameIndex --;
+ if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+ FullGuidToolDefinition[FileNameIndex] = 0;
+ break;
+ }
+ }
+ //
+ // Build the path list for Config file scan. The priority is below.
+ // 1. Scan the current path
+ // 2. Scan the same path with the application itself
+ // 3. Scan the current %PATH% of OS environment
+ // 4. Use the build-in default configuration
+ //
+ PathList = getenv("PATH");
+ if (PathList == NULL) {
+ Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
+ return 1;
+ }
+ EnvLen = strlen(PathList);
+ NewPathList = (char *)calloc(
+ strlen (".")
+ + strlen (";")
+ + strlen (FullGuidToolDefinition)
+ + strlen (";")
+ + EnvLen
+ + 1,
+ sizeof(char)
+ );
+ if (NewPathList == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ PathList = NULL;
+ free (PathList);
+ return 1;
+ }
+#ifndef __GNUC__
+ sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList);
+#else
+ sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList);
+#endif
+ PathList = NULL;
+ free (PathList);
+
+ //
+ // Load Guid Tools definition
+ //
+ InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
+ free (NewPathList);
+ if (InFilePath != NULL) {
+ printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath);
+ mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+ free (InFilePath);
+ } else {
+ //
+ // Use the pre-defined standard guided tools.
+ //
+ printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n");
+ mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
+ }
+
+ if ((strcmp(Argv[0], "-v") == 0) || (strcmp(Argv[0], "-V") == 0)) {
+ //
+ // View the FD binary image information.
+ //
+ if (Argc <= 1) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage ();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ Status = FmmtImageView(Argv[1], NULL, TRUE, NULL);
+
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while view the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+
+ } else if ((strcmp(Argv[0], "-d") == 0) || (strcmp(Argv[0], "-D") == 0)) {
+ //
+ // Delete some named FFS file from FD binary image.
+ //
+ if (!((Argc == 4) || ((Argc - 3) % 2 == 0))) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage ();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ if ((Argc - 3) % 2 == 0) {
+ FileData = malloc(sizeof (Data) * (Argc - 3)/2);
+ if (FileData == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return 1;
+ }
+ for(index = 0; index < (Argc - 3)/2; index ++) {
+ p = malloc(sizeof (FILENode));
+ if (p == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ return 1;
+ }
+ p -> FileName = Argv[3 + index * 2];
+ p -> SubLevel = 0;
+ exist = -1;
+ for (j = 0; j < count; j ++) {
+ if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
+ exist = j;
+ break;
+ }
+ }
+ if (exist >= 0) {
+ p -> Next = (FileData + j) -> OldFile;
+ (FileData + j) -> OldFile = p;
+ } else {
+ (FileData + count) -> NewFile = NULL;
+ (FileData + count) -> FdData = NULL;
+ (FileData + count) -> FvLevel = 0;
+ (FileData + count) -> FvInFd = NULL;
+ (FileData + count) -> FvId = Argv[2 + index * 2];;
+ (FileData + count) -> OldFile = p;
+ p -> Next = NULL;
+ count ++;
+ }
+ }
+
+ if (count <= 0) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ }
+ for (index = 0; index < count; index ++) {
+ for (j = index + 1; j < count; j ++) {
+ if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+ CHAR8 *tmp = (FileData + index)->FvId;
+ FILENode *t = (FileData + index)->OldFile;
+ (FileData + index)->FvId = (FileData + j)->FvId;
+ (FileData + index)-> OldFile = (FileData + j)->OldFile;
+ (FileData + j)-> OldFile = t;
+ (FileData + j)-> FvId = tmp;
+ }
+ }
+ }
+
+ //
+ // Delete some FFS file
+ //
+ Status = FmmtImageDelete(Argv[1], FileData, count, Argv[Argc-1]);
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index) ->NewFile != NULL) {
+ free ((FileData + index)->NewFile);
+ (FileData + index)->NewFile = NULL;
+ }
+ if ((FileData + index)->OldFile != NULL) {
+ free ((FileData + index)->OldFile);
+ (FileData + index)->OldFile = NULL;
+ }
+ }
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->FdData != NULL) {
+ LibFmmtFreeFd ((FileData + index)->FdData);
+ }
+ }
+ free (FileData);
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while delete some named ffs file from the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+ } else {
+ //
+ // Delete FV
+ //
+ Status = FmmtImageDeleteFv(Argv[1], Argv[2], Argv[3]);
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while delete the entire FV from the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+ }
+
+ } else if ((strcmp(Argv[0], "-a") == 0) || (strcmp(Argv[0], "-A") == 0)) {
+ //
+ // Add some named FFS file into FD binary image.
+ //
+ if ((Argc - 3 ) % 2 != 0) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage ();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ //
+ // Check whether the new added file exist or not.
+ //
+ for (index = 1; index < (Argc - 1) / 2; index ++) {
+ CheckFileExist = fopen(Argv[2 * index + 1], "rb");
+ if (CheckFileExist == NULL) {
+ Error("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[2 * index + 1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+ }
+
+ FileData = malloc(sizeof (Data) * (Argc - 3)/2);
+ if (FileData == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return 1;
+ }
+ for(index = 0; index < (Argc - 3)/2; index ++) {
+ p = malloc(sizeof (FILENode));
+ if (p == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ return 1;
+ }
+ p -> FileName = Argv[3 + index * 2];
+ p -> SubLevel = 0;
+ exist = -1;
+ for (j = 0; j < count; j ++) {
+ if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
+ exist = j;
+ break;
+ }
+ }
+ if (exist >= 0) {
+ p -> Next = (FileData + j) -> NewFile;
+ (FileData + j) -> NewFile = p;
+ } else {
+ (FileData + count) -> OldFile = NULL;
+ (FileData + count) -> FdData = NULL;
+ (FileData + count) -> FvLevel = 0;
+ (FileData + count) -> FvInFd = NULL;
+ (FileData + count) -> FvId = Argv[2 + index * 2];
+ (FileData + count) -> NewFile = p;
+ p -> Next = NULL;
+ count ++;
+ }
+ }
+
+ if (count <= 0) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ }
+
+ for (index = 0; index < count; index ++) {
+ for (j = index + 1; j < count; j ++) {
+ if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+ CHAR8 *tmp = (FileData + index)->FvId;
+ FILENode *temp = (FileData + index)->NewFile;
+ (FileData + index)->FvId = (FileData + j)->FvId;
+ (FileData + index)-> NewFile = (FileData + j)->NewFile;
+ (FileData + j)-> NewFile = temp;
+ (FileData + j)-> FvId = tmp;
+ }
+ }
+ }
+
+ Status = FmmtImageAdd(Argv[1], FileData, count, Argv[Argc-1]);
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->NewFile != NULL) {
+ free ((FileData + index)->NewFile);
+ (FileData + index)->NewFile = NULL;
+ }
+ if ((FileData + index)->OldFile != NULL) {
+ free ((FileData + index)->OldFile);
+ (FileData + index)->OldFile = NULL;
+ }
+ }
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->FdData != NULL) {
+ LibFmmtFreeFd ((FileData + index)->FdData);
+ }
+ }
+ free (FileData);
+
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while add some named ffs file into the FD image file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+
+ } else if ((strcmp(Argv[0], "-r") == 0) || (strcmp(Argv[0], "-R") == 0)) {
+ //
+ // Replace some named FFS file in the FD binary.
+ //
+ if ((Argc - 3) % 3 != 0) {
+ Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
+ Usage();
+ return 1;
+ }
+
+ //
+ // Open the file containing the FV to check whether it exist or not
+ //
+ CheckFileExist = fopen (Argv[1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+
+ //
+ // Check whether the new FFS file exist or not.
+ //
+ for (index = 1; index < Argc/3; index ++) {
+ CheckFileExist = fopen(Argv[3 * index + 1], "rb");
+ if (CheckFileExist == NULL) {
+ Error ("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[3 * index + 1]);
+ return 1;
+ }
+ fclose(CheckFileExist);
+ }
+
+ FileData = malloc(sizeof (Data) * (Argc - 3)/3);
+ if (FileData == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return 1;
+ }
+ for(index = 0; index < (Argc - 3)/3; index ++) {
+ p = malloc(sizeof (FILENode)); //p for old file
+ if (p == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ return 1;
+ }
+ q = malloc(sizeof (FILENode)); //q for new file
+ if (q == NULL) {
+ Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (FileData);
+ free (p);
+ return 1;
+ }
+ p -> FileName = Argv[3 + index * 3];
+ q -> FileName = Argv[4 + index * 3];
+ p -> SubLevel = 0;
+ q -> SubLevel = 0;
+ exist = -1;
+ for (j = 0; j < count; j ++) {
+ if ((strcmp(Argv[2 + index * 3], (FileData + j) -> FvId) == 0)) {
+ exist = j;
+ break;
+ }
+ }
+ if (exist >= 0) {
+ p -> Next = (FileData + j) -> OldFile;
+ (FileData + j) -> OldFile = p;
+ q -> Next = (FileData + j) -> NewFile;
+ (FileData + j) -> NewFile = q;
+ } else {
+ (FileData + count) -> FdData = NULL;
+ (FileData + count) -> FvLevel = 0;
+ (FileData + count) -> FvInFd = NULL;
+ (FileData + count) -> FvId = Argv[2 + index * 3];;
+ (FileData + count) -> OldFile = p;
+ (FileData + count) -> NewFile = q;
+ p -> Next = NULL;
+ q -> Next = NULL;
+ count ++;
+ }
+ }
+
+ if (count <= 0) {
+ Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
+ }
+ for (index = 0; index < count; index ++) {
+ for (j = index + 1; j < count; j ++) {
+ if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
+ CHAR8 *tmp = (FileData + index)->FvId;
+ FILENode *Old = (FileData + index)->OldFile;
+ FILENode *New = (FileData + index)->NewFile;
+ (FileData + index)->FvId = (FileData + j)->FvId;
+ (FileData + index)->OldFile = (FileData + j)->OldFile;
+ (FileData + index)->NewFile = (FileData + j)->NewFile;
+ (FileData + j)->OldFile = Old;
+ (FileData + j)->NewFile = New;
+ (FileData + j)->FvId = tmp;
+ }
+ }
+ }
+
+ Status = FmmtImageReplace(Argv[1], FileData, count, Argv[Argc-1]);
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->NewFile != NULL) {
+ free ((FileData + index)->NewFile);
+ (FileData + index)->NewFile = NULL;
+ }
+ if ((FileData + index)->OldFile != NULL) {
+ free ((FileData + index)->OldFile);
+ (FileData + index)->OldFile = NULL;
+ }
+ }
+ for (index = 0; index < count; index ++) {
+ if ((FileData + index)->FdData != NULL) {
+ LibFmmtFreeFd ((FileData + index)->FdData);
+ }
+ }
+ free (FileData);
+ if (EFI_ERROR (Status)) {
+ Error("FMMT", 0, 1001, "Error while replace the named ffs file in the FD image file with the new ffs file.", "");
+ LibRmDir (TemDir);
+ return 1;
+ }
+
+ } else if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
+ (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
+ //
+ // print help information to user.
+ //
+ Usage();
+
+ } else {
+ //
+ // Invalid parameter.
+ //
+ printf("\n");
+ Error("FMMT", 0, 1001, "Invalid parameter", Argv[0]);
+ Usage();
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
new file mode 100644
index 0000000000..ec8e3eaba0
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
@@ -0,0 +1,479 @@
+/** @file
+
+ Structures and functions declaration.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BIN_FILE_MANAGER_
+#define _BIN_FILE_MANAGER_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <FvLib.h>
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Common/PiFirmwareFile.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "ParseInf.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "Compress.h"
+#include "Decompress.h"
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#ifdef __GNUC__
+#define OS_SEP '/'
+#define OS_SEP_STR "/"
+#define COPY_STR "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR "rm -r \"%s\" > /dev/null"
+#define DEL_STR "rm \"%s\" > /dev/null"
+#else
+#define OS_SEP '\\'
+#define OS_SEP_STR "\\"
+#define COPY_STR "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR "del \"%s\" > NUL"
+#endif
+
+#define UTILITY_NAME "Firmware Module Management Tool(FMMT)"
+#define UTILITY_SHORT_NAME "FMMT"
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 23
+#define MAX_BASENAME_LEN 60 // not good to HardCode, but let's be reasonable
+#define EFI_SECTION_ERROR EFIERR (100)
+//
+// The maximum number of Pad file guid entries.
+//
+#define MAX_NUMBER_OF_PAD_FILE_GUIDS 1024
+
+//
+// The maximum number of block map entries supported by the library
+//
+#define MAX_NUMBER_OF_FV_BLOCKS 100
+
+
+//
+// The maximum number of sections in an FFS file.
+//
+#define MAX_NUMBER_OF_SECTION_IN_FFS 100
+
+//
+// The maximum number of files in the FV supported by the library
+//
+#define MAX_NUMBER_OF_FILES_IN_FV 1000
+#define MAX_NUMBER_OF_FILES_IN_CAP 1000
+
+
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE is only used by DXE driver.
+///
+#define EFI_DEP_BEFORE 0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER is only used by DXE driver.
+///
+#define EFI_DEP_AFTER 0x01
+
+#define EFI_DEP_PUSH 0x02
+#define EFI_DEP_AND 0x03
+#define EFI_DEP_OR 0x04
+#define EFI_DEP_NOT 0x05
+#define EFI_DEP_TRUE 0x06
+#define EFI_DEP_FALSE 0x07
+#define EFI_DEP_END 0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR 0x09
+
+//
+// INF file strings
+//
+#define OPTIONS_SECTION_STRING "[options]"
+#define ATTRIBUTES_SECTION_STRING "[attributes]"
+#define FILES_SECTION_STRING "[files]"
+#define FV_BASE_ADDRESS_STRING "[FV_BASE_ADDRESS]"
+
+//
+// Options section
+//
+#define EFI_FV_BASE_ADDRESS_STRING "EFI_BASE_ADDRESS"
+#define EFI_FV_FILE_NAME_STRING "EFI_FILE_NAME"
+#define EFI_NUM_BLOCKS_STRING "EFI_NUM_BLOCKS"
+#define EFI_BLOCK_SIZE_STRING "EFI_BLOCK_SIZE"
+#define EFI_GUID_STRING "EFI_GUID"
+#define EFI_FV_FILESYSTEMGUID_STRING "EFI_FV_GUID"
+#define EFI_FV_NAMEGUID_STRING "EFI_FVNAME_GUID"
+#define EFI_CAPSULE_GUID_STRING "EFI_CAPSULE_GUID"
+#define EFI_CAPSULE_HEADER_SIZE_STRING "EFI_CAPSULE_HEADER_SIZE"
+#define EFI_CAPSULE_FLAGS_STRING "EFI_CAPSULE_FLAGS"
+#define EFI_CAPSULE_VERSION_STRING "EFI_CAPSULE_VERSION"
+
+#define EFI_FV_TOTAL_SIZE_STRING "EFI_FV_TOTAL_SIZE"
+#define EFI_FV_TAKEN_SIZE_STRING "EFI_FV_TAKEN_SIZE"
+#define EFI_FV_SPACE_SIZE_STRING "EFI_FV_SPACE_SIZE"
+
+
+typedef UINT32 FMMT_ENCAP_TYPE;
+
+#define MAX_LEVEL_IN_FV_FILE 32
+
+//
+// Types of FMMT_ENCAP_TREENODE_TYPE
+//
+#define FMMT_ENCAP_TREE_FV 0x1
+#define FMMT_ENCAP_TREE_FFS 0x2
+#define FMMT_ENCAP_TREE_GUIDED_SECTION 0x3
+#define FMMT_ENCAP_TREE_COMPRESS_SECTION 0x4
+#define FMMT_ENCAP_TREE_FV_SECTION 0x5
+
+extern EFI_HANDLE mParsedGuidedSectionTools;
+
+
+#define TEMP_DIR_NAME "FmmtTemp"
+
+//
+// Structure to keep a list of GUID-To-BaseNames
+//
+typedef struct _GUID_TO_BASENAME {
+ struct _GUID_TO_BASENAME *Next;
+ INT8 Guid[PRINTED_GUID_BUFFER_SIZE];
+ INT8 BaseName[MAX_BASENAME_LEN];
+} GUID_TO_BASENAME;
+
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+ EFI_GUID Guid;
+ CHAR8* Name;
+ CHAR8* Path;
+ struct _GUID_SEC_TOOL_ENTRY *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+
+//
+// Private data types
+//
+//
+// Component information
+//
+typedef struct {
+ UINTN Size;
+ CHAR8 ComponentName[_MAX_PATH];
+} COMPONENT_INFO;
+
+typedef struct {
+ CHAR8 FfsName[_MAX_PATH];
+
+ //
+ // UI Name for this FFS file, if has.
+ //
+ CHAR16 UiName[_MAX_PATH];
+ UINT32 UiNameSize;
+ //
+ // Total section number in this FFS.
+ //
+ UINT32 TotalSectionNum;
+
+ //
+ // Describe the position of the FFS file.
+ //
+ UINT8 Level;
+ //
+ // If this FFS has no encapsulate section, this flag will set to True.
+ //
+ BOOLEAN IsLeaf;
+ //
+ // Section type for each section in FFS.
+ //
+ EFI_SECTION_TYPE SectionType[MAX_NUMBER_OF_SECTION_IN_FFS];
+ //
+ // Offset relative to current FV
+ //
+ UINT32 Offset;
+ UINT8 FvLevel;
+ EFI_GUID GuidName;
+ UINT8 *Depex;
+ UINT32 DepexLen;
+ BOOLEAN IsHandle;
+ BOOLEAN IsFvStart;
+ BOOLEAN IsFvEnd;
+}FFS_ATTRIBUTES;
+
+
+typedef struct __ENCAP_INFO_DATA{
+ //
+ // Now Level
+ //
+ UINT8 Level;
+
+ //
+ // Encapsulate type.
+ //
+ FMMT_ENCAP_TYPE Type;
+
+ //
+ // Data, if it's FV, should be FV header.
+ //
+ VOID *Data;
+
+ //
+ //FvId, match FvId with FvGuidName.
+ //
+ UINT8 FvId;
+
+ //
+ // if FV ExtHeaderOffset not to zero, should also have FvExtHeader information
+ //
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+ CHAR16 UiName[_MAX_PATH];
+ UINT32 UiNameSize;
+ UINT8 *Depex;
+ UINT32 DepexLen;
+
+ //
+ // Next node.
+ //
+ struct __ENCAP_INFO_DATA *NextNode;
+
+ //
+ // Right node.
+ //
+ struct __ENCAP_INFO_DATA *RightNode;
+} ENCAP_INFO_DATA;
+
+typedef struct _FFS_INFOMATION{
+ CHAR8 *FFSName;
+ UINT32 InFvId;
+ UINT8 ParentLevel;
+ BOOLEAN IsFFS;
+ CHAR16 UiName[_MAX_PATH];
+ UINT32 UiNameSize;
+ UINT8 *Depex;
+ UINT32 DepexLen;
+ BOOLEAN FfsFoundFlag;
+ struct _FFS_INFOMATION *Next;
+} FFS_INFORMATION;
+
+//
+// FV and capsule information holder
+//
+typedef struct _FV_INFOMATION{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+ UINT32 ImageAddress;
+ UINT32 FfsNumbers;
+ CHAR8 FvName[_MAX_PATH];
+ EFI_FV_BLOCK_MAP_ENTRY FvBlocks[MAX_NUMBER_OF_FV_BLOCKS];
+ FFS_ATTRIBUTES FfsAttuibutes[MAX_NUMBER_OF_FILES_IN_FV];
+ EFI_FFS_FILE_HEADER2 FfsHeader[MAX_NUMBER_OF_FILES_IN_FV];
+ struct _FV_INFOMATION *FvNext;
+ ENCAP_INFO_DATA *EncapData;
+ UINT8 FvLevel;
+ CHAR8 *FvUiName;
+ UINT8 MulFvLevel;
+ CHAR8 AlignmentStr[16];
+ FFS_INFORMATION *ChildFvFFS;
+} FV_INFORMATION;
+
+typedef struct _FIRMWARE_DEVICE {
+ ///
+ /// Size of FD file
+ ///
+ UINT32 Size;
+ FV_INFORMATION *Fv;
+} FIRMWARE_DEVICE;
+
+typedef struct _FILENode {
+ CHAR8 *FileName;
+ UINT8 SubLevel;
+ struct _FILENode *Next;
+} FILENode;
+
+typedef struct {
+ CHAR8 *FvId;
+ FILENode *NewFile;
+ FILENode *OldFile;
+ FIRMWARE_DEVICE *FdData;
+ UINT8 FvLevel;
+ FV_INFORMATION *FvInFd;
+} Data;
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+);
+
+/**
+
+ TODO: Add function description
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN ENCAP_INFO_DATA **CurrentFvEncapData,
+ IN UINT32 *FfsCount,
+ IN OUT UINT8 *FvCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ );
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ );
+
+ /**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ );
+
+/**
+ Converts ASCII characters to Unicode.
+ Assumes that the Unicode characters are only these defined in the ASCII set.
+
+ String - Pointer to string that is written to FILE.
+ UniString - Pointer to unicode string
+
+ The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+ IN CHAR8 *String,
+ OUT CHAR16 *UniString
+ );
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+ );
+
+/**
+ Delete a file.
+
+ @param[in] FileName Name of the file need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibFmmtDeleteFile(
+ IN CHAR8 *FileName
+);
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibFmmtFreeFd (
+ FIRMWARE_DEVICE *Fd
+);
+
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ IN ENCAP_INFO_DATA *CurrentEncapData,
+ IN UINT32 Level_Break,
+ OUT FFS_INFORMATION **OutputFile
+);
+
+
+EFI_STATUS
+LibLocateFvViaFvId (
+ IN FIRMWARE_DEVICE *FdData,
+ IN CHAR8 *FvId,
+ IN OUT FV_INFORMATION **FvInFd
+);
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+);
+
+EFI_STATUS
+FvBufGetSize(
+IN VOID *Fv,
+OUT UINTN *Size
+);
+
+EFI_STATUS
+FvBufFindNextFile(
+IN VOID *Fv,
+IN OUT UINTN *Key,
+OUT VOID **File
+);
+#endif
diff --git a/Platform/Intel/Tools/FMMT/FmmtConf.ini b/Platform/Intel/Tools/FMMT/FmmtConf.ini
new file mode 100644
index 0000000000..36135116b3
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/FmmtConf.ini
@@ -0,0 +1,6 @@
+a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress
+ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress
+fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32
+d42ae6bd-1352-4bfb-909a-ca72a6eae889 LZMAF86 LzmaF86Compress
+3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress
+
diff --git a/Platform/Intel/Tools/FMMT/FmmtLib.c b/Platform/Intel/Tools/FMMT/FmmtLib.c
new file mode 100644
index 0000000000..f87042114b
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/FmmtLib.c
@@ -0,0 +1,5051 @@
+/** @file
+
+ Library to parse and generate FV image.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FirmwareModuleManagement.h"
+
+#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
+ ( \
+ (BOOLEAN) ( \
+ (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
+ ) \
+ )
+
+CHAR8 mFirmwareFileSystem2Guid[16] = {0x78, 0xE5, 0x8C, 0x8C, 0x3D, 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3};
+
+CHAR8 mFirmwareFileSystem3Guid[16] = {0x7A, 0xC0, 0x73, 0x54, 0xCB, 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A };
+
+EFI_GUID mEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
+extern CHAR8* mGuidToolDefinition;
+
+static CHAR8 *mSectionTypeName[] = {
+ NULL, // 0x00 - reserved
+ "EFI_SECTION_COMPRESSION", // 0x01
+ "EFI_SECTION_GUID_DEFINED", // 0x02
+ NULL, // 0x03 - reserved
+ NULL, // 0x04 - reserved
+ NULL, // 0x05 - reserved
+ NULL, // 0x06 - reserved
+ NULL, // 0x07 - reserved
+ NULL, // 0x08 - reserved
+ NULL, // 0x09 - reserved
+ NULL, // 0x0A - reserved
+ NULL, // 0x0B - reserved
+ NULL, // 0x0C - reserved
+ NULL, // 0x0D - reserved
+ NULL, // 0x0E - reserved
+ NULL, // 0x0F - reserved
+ "EFI_SECTION_PE32", // 0x10
+ "EFI_SECTION_PIC", // 0x11
+ "EFI_SECTION_TE", // 0x12
+ "EFI_SECTION_DXE_DEPEX", // 0x13
+ "EFI_SECTION_VERSION", // 0x14
+ "EFI_SECTION_USER_INTERFACE", // 0x15
+ "EFI_SECTION_COMPATIBILITY16", // 0x16
+ "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17
+ "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18
+ "EFI_SECTION_RAW", // 0x19
+ NULL, // 0x1A
+ "EFI_SECTION_PEI_DEPEX", // 0x1B
+ "EFI_SECTION_SMM_DEPEX" // 0x1C
+};
+
+
+static CHAR8 *mFfsFileType[] = {
+ NULL, // 0x00
+ "EFI_FV_FILETYPE_RAW", // 0x01
+ "EFI_FV_FILETYPE_FREEFORM", // 0x02
+ "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03
+ "EFI_FV_FILETYPE_PEI_CORE", // 0x04
+ "EFI_FV_FILETYPE_DXE_CORE", // 0x05
+ "EFI_FV_FILETYPE_PEIM", // 0x06
+ "EFI_FV_FILETYPE_DRIVER", // 0x07
+ "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
+ "EFI_FV_FILETYPE_APPLICATION", // 0x09
+ "EFI_FV_FILETYPE_SMM", // 0x0A
+ "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
+ "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C
+ "EFI_FV_FILETYPE_SMM_CORE" // 0x0D
+ };
+
+static CHAR8 *mGuidSectionAttr[] = {
+ "NONE", // 0x00
+ "PROCESSING_REQUIRED", // 0x01
+ "AUTH_STATUS_VALID" // 0x02
+};
+
+static EFI_GUID mFvUiGuid = {
+ 0xA67DF1FA, 0x8DE8, 0x4E98, {
+ 0xAF, 0x09, 0x4B, 0xDF, 0x2E, 0xFF, 0xBC, 0x7C
+ }
+};
+
+
+/**
+ Generate the unique template filename.
+**/
+CHAR8 *
+GenTempFile (
+ VOID
+ )
+{
+ CHAR8 *TemString;
+ TemString = NULL;
+#ifndef __GNUC__
+ TemString = CloneString (tmpnam (NULL));
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ TemString = CloneString(tmp);
+ close(Fdtmp);
+#endif
+ return TemString;
+}
+
+static
+EFI_STATUS
+LibExtractFvUiName(CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader, CHAR8 **FvUiName)
+{
+ UINT8 *ExtEnd;
+ UINT32 ExtDataSize;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntry;
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *GuidEntry;
+
+
+ ExtEnd = (UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize;
+ ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(FvExtHeader + 1);
+ while ((UINT8 *)ExtEntry < ExtEnd) {
+ //
+ // GUID type EXT
+ //
+ if (ExtEntry->ExtEntryType == 0x0002) {
+ GuidEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *)ExtEntry;
+ if (memcmp(&GuidEntry->FormatType, &mFvUiGuid, sizeof(EFI_GUID)) == 0) {
+ ExtDataSize = ExtEntry->ExtEntrySize - (sizeof(EFI_GUID)+sizeof(*ExtEntry));
+ *FvUiName = malloc(ExtDataSize + 1);
+ if (*FvUiName != NULL) {
+ memcpy(*FvUiName, (UINT8 *)GuidEntry + sizeof(EFI_GUID)+sizeof(*ExtEntry), ExtDataSize);
+ (*FvUiName)[ExtDataSize] = '\0';
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtEntry + ExtEntry->ExtEntrySize);
+ }
+ return EFI_NOT_FOUND;
+}
+
+FV_INFORMATION *
+LibInitializeFvStruct (
+ FV_INFORMATION *Fv
+)
+{
+ UINT32 Index;
+
+ if (Fv == NULL) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index ++) {
+ memset (Fv->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+ memset (Fv->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+ memset (&Fv->FfsAttuibutes[Index].GuidName, '\0', sizeof(EFI_GUID));
+ Fv->FfsAttuibutes[Index].UiNameSize = 0;
+ Fv->FfsAttuibutes[Index].IsLeaf = TRUE;
+ Fv->FfsAttuibutes[Index].Level = 0xFF;
+ Fv->FfsAttuibutes[Index].TotalSectionNum = 0;
+ Fv->FfsAttuibutes[Index].Depex = NULL;
+ Fv->FfsAttuibutes[Index].DepexLen = 0;
+ Fv->FfsAttuibutes[Index].IsHandle = FALSE;
+ Fv->FfsAttuibutes[Index].IsFvStart = FALSE;
+ Fv->FfsAttuibutes[Index].IsFvEnd = FALSE;
+ }
+
+ Fv->EncapData = NULL;
+ Fv->FvNext = NULL;
+ Fv->ChildFvFFS = NULL;
+ Fv->FvLevel = 0;
+ Fv->MulFvLevel = 1;
+ strcpy(Fv->AlignmentStr,"8");
+ return Fv;
+}
+
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+)
+{
+ FIRMWARE_DEVICE *LocalFdData;
+ UINT16 Index;
+ CHAR8 Ffs2Guid[16];
+ CHAR8 SignatureCheck[5] = "";
+ CHAR8 Signature[5] = "_FVH";
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *NewFoundFv;
+ BOOLEAN FirstMatch;
+ UINT32 FdSize;
+ UINT16 FvCount;
+ UINT8 *FdBuffer;
+ UINT8 *FdBufferEnd;
+ UINT8 *FdBufferOri;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+
+ CurrentFv = NULL;
+ NewFoundFv = NULL;
+ FdBuffer = NULL;
+ FdBufferOri = NULL;
+ FirstMatch = TRUE;
+ Index = 0;
+ FdSize = 0;
+ FvCount = 0;
+ LocalFdData = NULL;
+
+ if (InputFile == NULL) {
+ Error ("FMMT", 0, 0001, "Error opening the input file", "");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Find each FVs in the FD
+ //
+
+ fseek(InputFile,0,SEEK_SET);
+ fseek(InputFile,0,SEEK_END);
+
+ FdSize = ftell(InputFile);
+
+ fseek(InputFile,0,SEEK_SET);
+ //
+ // Create an FD structure to store useful information.
+ //
+ LocalFdData = (FIRMWARE_DEVICE *) malloc (sizeof (FIRMWARE_DEVICE));
+ if (LocalFdData == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ LocalFdData->Fv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION));
+ if (LocalFdData->Fv == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LibInitializeFvStruct (LocalFdData->Fv);
+
+ //
+ // Readout the FD file data to buffer.
+ //
+ FdBuffer = malloc (FdSize);
+
+ if (FdBuffer == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (FdBuffer, 1, FdSize, InputFile) != FdSize) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Read FD file error!");
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ FdBufferOri = FdBuffer;
+ FdBufferEnd = FdBuffer + FdSize;
+
+ while (FdBuffer <= FdBufferEnd - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FdBuffer;
+ //
+ // Copy 4 bytes of fd data to check the _FVH signature
+ //
+ memcpy (SignatureCheck, &FvHeader->Signature, 4);
+
+ if (strncmp(SignatureCheck, Signature, 4) == 0){
+ //
+ // Still need to determine the FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER equal to
+ // EFI_FIRMWARE_FILE_SYSTEM2_GUID or EFI_FIRMWARE_FILE_SYSTEM3_GUID.
+ // Turn back 28 bytes to find the GUID.
+ //
+ memcpy (Ffs2Guid, &FvHeader->FileSystemGuid, 16);
+
+ //
+ // Compare GUID.
+ //
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem2Guid[Index]) {
+ break;
+ }
+ }
+ if (Index != 16) {
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem3Guid[Index]) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Here we found an FV.
+ //
+ if ((Index == 16) && ((FdBuffer + FvHeader->FvLength) <= FdBufferEnd)) {
+ if (FirstMatch) {
+ LocalFdData->Fv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri);
+ CurrentFv = LocalFdData->Fv;
+ CurrentFv->FvNext = NULL;
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(CurrentFv->FvName, "FV%d", FvCount);
+
+ FirstMatch = FALSE;
+ } else {
+ NewFoundFv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION));
+ if (NewFoundFv == NULL) {
+ Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error");
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LibInitializeFvStruct (NewFoundFv);
+
+ //
+ // Need to turn back 0x2c bytes
+ //
+ NewFoundFv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri);
+
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(NewFoundFv->FvName, "FV%d", FvCount);
+
+ //
+ // Value it to NULL for found FV usage.
+ //
+ NewFoundFv->FvNext = NULL;
+ CurrentFv->FvNext = NewFoundFv;
+
+ //
+ // Make the CurrentFv point to next FV.
+ //
+ CurrentFv = CurrentFv->FvNext;
+ }
+
+ FvCount ++;
+ FdBuffer = FdBuffer + FvHeader->FvLength;
+ } else {
+ FdBuffer ++;
+ }
+
+ } else {
+ FdBuffer ++;
+ }
+ }
+
+ LocalFdData->Size = FdSize;
+
+ *FdData = LocalFdData;
+
+ free (FdBufferOri);
+
+ return EFI_SUCCESS;
+}
+
+UINTN
+GetFreeOffset (
+ IN VOID *InputFv
+)
+{
+ UINTN FreeOffset;
+ UINTN Offset;
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+
+ Offset = 0;
+ CurrentFile = NULL;
+ FreeOffset = 0;
+ do {
+ FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8);
+ Status = FvBufFindNextFile(InputFv, &Offset, (VOID **)&CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ break;
+ }
+ else if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } while (CurrentFile != NULL);
+
+ return FreeOffset;
+}
+
+/*
+ Construct a set of blank chars based on the number.
+
+ @param[in] Count The number of blank chars.
+
+ @return A string contained the blank chars.
+
+*/
+CHAR8 *
+LibConstructBlankChar (
+ IN UINT8 Count
+)
+{
+ CHAR8 *RetStr;
+ UINT8 Index;
+
+ Index = 0;
+ RetStr = NULL;
+
+ RetStr = (CHAR8 *) malloc (Count +1);
+
+ if (RetStr == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return NULL;
+ }
+
+ memset (RetStr , '\0', Count + 1);
+
+ for (Index=0; Index <= Count -1; Index ++) {
+ RetStr[Index] = ' ';
+ }
+
+ return RetStr;
+
+}
+
+/**
+
+ This function determines the size of the FV and the erase polarity. The
+ erase polarity is the FALSE value for file state.
+
+
+ @param[in ] InputFile The file that contains the FV image.
+ @param[out] FvSize The size of the FV.
+ @param[out] ErasePolarity The FV erase polarity.
+
+ @return EFI_SUCCESS Function completed successfully.
+ @return EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
+ @return EFI_ABORTED The function encountered an error.
+
+**/
+EFI_STATUS
+LibReadFvHeader (
+ IN VOID *InputFv,
+ IN BOOLEAN ViewFlag,
+ IN UINT8 FvLevel,
+ IN UINT8 FvCount,
+ IN CHAR8 *FvName
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader;
+ CHAR8 *BlankSpace;
+ CHAR8 *FvUiName;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+ BlankSpace = NULL;
+ FvUiName = NULL;
+
+ //
+ // Check input parameters
+ //
+ if (InputFv == NULL) {
+ Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Read the header
+ //
+ VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) InputFv;
+
+
+ BlankSpace = LibConstructBlankChar((FvLevel)*2);
+
+ if (BlankSpace == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+
+ if (ViewFlag) {
+ if ((FvLevel -1) == 0) {
+ printf ("\n%s :\n", FvName);
+ } else {
+ printf ("%sChild FV named FV%d of %s\n", BlankSpace, FvCount, FvName);
+ }
+ }
+
+ //
+ // Print FV header information
+ //
+ if (ViewFlag) {
+ printf ("\n%sAttributes: %X\n", BlankSpace, (unsigned) VolumeHeader->Attributes);
+ printf ("%sTotal Volume Size: 0x%08X\n", BlankSpace, (unsigned) VolumeHeader->FvLength);
+ printf ("%sFree Volume Size: 0x%08X\n", BlankSpace, (unsigned) (VolumeHeader->FvLength - GetFreeOffset(InputFv)));
+ }
+
+ if (ViewFlag && VolumeHeader->ExtHeaderOffset != 0) {
+ FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)VolumeHeader + VolumeHeader->ExtHeaderOffset);
+ printf("%sFvNameGuid: %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+ BlankSpace,
+ FvExtHeader->FvName.Data1,
+ FvExtHeader->FvName.Data2,
+ FvExtHeader->FvName.Data3,
+ FvExtHeader->FvName.Data4[0],
+ FvExtHeader->FvName.Data4[1],
+ FvExtHeader->FvName.Data4[2],
+ FvExtHeader->FvName.Data4[3],
+ FvExtHeader->FvName.Data4[4],
+ FvExtHeader->FvName.Data4[5],
+ FvExtHeader->FvName.Data4[6],
+ FvExtHeader->FvName.Data4[7]);
+ LibExtractFvUiName(FvExtHeader, &FvUiName);
+ if (FvUiName != NULL && FvLevel == 1) {
+ printf("%sFV UI Name: %s\n\n", BlankSpace, FvUiName);
+ }
+ free(FvUiName);
+ }
+ free (BlankSpace);
+ return EFI_SUCCESS;
+}
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+
+ UINTN BytesRead;
+ UINT32 Size;
+ EFI_FV_BLOCK_MAP_ENTRY BlockMap;
+
+ BytesRead = 0;
+ Size = 0;
+
+ if (InputFile == NULL || FvSize == NULL) {
+ Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), SEEK_CUR);
+ do {
+ fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+
+ if (BlockMap.NumBlocks != 0) {
+ Size += BlockMap.NumBlocks * BlockMap.Length;
+ }
+ } while (!(BlockMap.NumBlocks == 0 && BlockMap.Length == 0));
+
+
+ *FvSize = Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Clears out all files from the Fv buffer in memory
+
+ @param[in] Fv - Address of the Fv in memory
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+FvBufGetSize (
+ IN VOID *Fv,
+ OUT UINTN *Size
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FV_BLOCK_MAP_ENTRY *blk;
+
+ *Size = 0;
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ blk = hdr->BlockMap;
+
+ while (blk->Length != 0 || blk->NumBlocks != 0) {
+ *Size = *Size + (blk->Length * blk->NumBlocks);
+ if (*Size >= 0x40000000) {
+ //
+ // If size is greater than 1GB, then assume it is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+ blk++;
+ }
+
+ if (*Size == 0) {
+ //
+ // If size is 0, then assume the volume is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Generate the leaf FFS files.
+
+*/
+EFI_STATUS
+LibGenFfsFile (
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ErasePolarity
+)
+{
+ UINT32 FfsFileSize;
+ CHAR8 *FfsFileName;
+ FILE *FfsFile;
+ CHAR8 *TempDir;
+
+
+ FfsFileSize = 0;
+ FfsFileName = NULL;
+ FfsFile = NULL;
+ TempDir = NULL;
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1);
+
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ FfsFileName = (CHAR8 *) malloc (_MAX_PATH);
+ if (FfsFileName == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ memset (FfsFileName, '\0', _MAX_PATH);
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ sprintf (
+ (CHAR8 *)FfsFileName,
+ "%s%cNum%d-%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X-Level%d",
+ TempDir,
+ OS_SEP,
+ *FfsCount,
+ (unsigned) CurrentFile->Name.Data1,
+ CurrentFile->Name.Data2,
+ CurrentFile->Name.Data3,
+ CurrentFile->Name.Data4[0],
+ CurrentFile->Name.Data4[1],
+ CurrentFile->Name.Data4[2],
+ CurrentFile->Name.Data4[3],
+ CurrentFile->Name.Data4[4],
+ CurrentFile->Name.Data4[5],
+ CurrentFile->Name.Data4[6],
+ CurrentFile->Name.Data4[7],
+ Level
+ );
+
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].FfsName, FfsFileName, strlen(FfsFileName));
+ memcpy (&CurrentFv->FfsAttuibutes[*FfsCount].GuidName, &CurrentFile->Name, sizeof(EFI_GUID));
+ //
+ // Update current FFS files file state.
+ //
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ FfsFile = fopen (FfsFileName, "wb+");
+ if (FfsFile == NULL) {
+ Error ("FMMT", 0, 0003, "error writing FFS file", "cannot Create a new ffs file.");
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) != FfsFileSize) {
+ Error ("FMMT", 0, 0004, "error writing FFS file", "cannot Create a new ffs file.");
+ fclose(FfsFile);
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ fclose(FfsFile);
+ free(FfsFileName);
+ FfsFileName = NULL;
+
+ CurrentFv->FfsNumbers = *FfsCount;
+
+ *FfsCount += 1;
+
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+Unicode2AsciiString (
+ IN CHAR16 *Source,
+ OUT CHAR8 *Destination
+ )
+ /*++
+
+ Routine Description:
+
+ Convert a null-terminated unicode string to a null-terminated ascii string.
+
+ Arguments:
+
+ Source - The pointer to the null-terminated input unicode string.
+ Destination - The pointer to the null-terminated output ascii string.
+
+ Returns:
+
+ N/A
+
+ --*/
+{
+ while (*Source != '\0') {
+ *(Destination++) = (CHAR8) *(Source++);
+ }
+ //
+ // End the ascii with a NULL.
+ //
+ *Destination = '\0';
+}
+
+
+/**
+
+ Parses EFI Sections, if the view flag turn on, then will collect FFS section information
+ and extract FFS files.
+
+ @param[in] SectionBuffer - Buffer containing the section to parse.
+ @param[in] BufferLength - Length of SectionBuffer
+ @param[in, out] CurrentFv
+ @param[in] FvName
+ @param[in] CurrentFile
+ @param[in] Level
+ @param[in, out] FfsCount
+ @param[in] ViewFlag
+ @param[in] ErasePolarity
+
+ @retval EFI_SECTION_ERROR - Problem with section parsing.
+ (a) compression errors
+ (b) unrecognized section
+ @retval EFI_UNSUPPORTED - Do not know how to parse the section.
+ @retval EFI_SUCCESS - Section successfully parsed.
+ @retval EFI_OUT_OF_RESOURCES - Memory allocation failed.
+
+--*/
+EFI_STATUS
+LibParseSection (
+ UINT8 *SectionBuffer,
+ UINT32 BufferLength,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ UINT8 Level,
+ ENCAP_INFO_DATA **CurrentFvEncapData,
+ UINT8 FfsLevel,
+ UINT32 *FfsCount,
+ UINT8 *FvCount,
+ BOOLEAN ViewFlag,
+ BOOLEAN ErasePolarity,
+ BOOLEAN *IsFfsGenerated
+ )
+{
+ UINT32 ParsedLength;
+ UINT8 *Ptr;
+ UINT32 SectionLength;
+ UINT32 UiSectionLength;
+ EFI_SECTION_TYPE Type;
+ EFI_STATUS Status;
+ CHAR8 *ExtractionTool;
+ CHAR8 *ToolInputFile;
+ CHAR8 *ToolOutputFile;
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ UINT8 *ToolOutputBuffer;
+ UINT32 ToolOutputLength;
+ CHAR16 *UIName;
+ UINT32 UINameSize;
+ BOOLEAN HasDepexSection;
+ UINT32 NumberOfSections;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ CHAR8 *BlankChar;
+ UINT8 *UncompressedBuffer;
+ UINT32 UncompressedLength;
+ UINT8 *CompressedBuffer;
+ UINT32 CompressedLength;
+ UINT8 CompressionType;
+ DECOMPRESS_FUNCTION DecompressFunction;
+ GETINFO_FUNCTION GetInfoFunction;
+ UINT32 DstSize;
+ UINT32 ScratchSize;
+ UINT8 *ScratchBuffer;
+ BOOLEAN EncapDataNeedUpdata;
+ CHAR8 *TempDir;
+ CHAR8 *ToolInputFileFullName;
+ CHAR8 *ToolOutputFileFullName;
+ UINT8 LargeHeaderOffset;
+ UINT16 GuidAttr;
+ UINT16 DataOffset;
+ CHAR8 *UIFileName;
+ CHAR8 *ToolInputFileName;
+ CHAR8 *ToolOutputFileName;
+
+ DataOffset = 0;
+ GuidAttr = 0;
+ ParsedLength = 0;
+ ToolOutputLength = 0;
+ UINameSize = 0;
+ NumberOfSections = 0;
+ UncompressedLength = 0;
+ CompressedLength = 0;
+ CompressionType = 0;
+ DstSize = 0;
+ ScratchSize = 0;
+ Ptr = NULL;
+ ExtractionTool = NULL;
+ ToolInputFile = NULL;
+ ToolOutputFile = NULL;
+ SystemCommand = NULL;
+ SystemCommandFormatString = NULL;
+ ToolOutputBuffer = NULL;
+ UIName = NULL;
+ LocalEncapData = NULL;
+ LocalEncapDataTemp = NULL;
+ BlankChar = NULL;
+ UncompressedBuffer = NULL;
+ CompressedBuffer = NULL;
+ ScratchBuffer = NULL;
+ TempDir = NULL;
+ ToolInputFileFullName = NULL;
+ ToolOutputFileFullName = NULL;
+ ToolInputFileName = NULL;
+ ToolOutputFileFullName = NULL;
+ HasDepexSection = FALSE;
+ EncapDataNeedUpdata = TRUE;
+ LargeHeaderOffset = 0;
+
+
+ while (ParsedLength < BufferLength) {
+ Ptr = SectionBuffer + ParsedLength;
+
+ SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if (SectionLength == 0xffffff && Type == 0xff) {
+ ParsedLength += 4;
+ continue;
+ }
+ //
+ //If Size is 0xFFFFFF then ExtendedSize contains the size of the section.
+ //
+ if (SectionLength == 0xffffff) {
+ SectionLength = ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSize;
+ LargeHeaderOffset = sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+
+ switch (Type) {
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+
+ EncapDataNeedUpdata = TRUE;
+
+ Level ++;
+ NumberOfSections ++;
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+ CurrentFv->FfsAttuibutes[*FfsCount].IsFvStart = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FV_SECTION;
+
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ //
+ LocalEncapData->Data = NULL;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ LocalEncapData->FvId = *FvCount;
+ }
+
+ //
+ //save parent level FFS file's GUID name
+ //
+ LocalEncapDataTemp = CurrentFv->EncapData;
+ while (LocalEncapDataTemp->NextNode != NULL) {
+ if (LocalEncapDataTemp->Level == FfsLevel) {
+ while (LocalEncapDataTemp->RightNode != NULL) {
+ LocalEncapDataTemp = LocalEncapDataTemp->RightNode;
+ }
+ if (LocalEncapDataTemp != NULL && LocalEncapDataTemp->FvExtHeader == NULL) {
+ LocalEncapDataTemp->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (LocalEncapDataTemp->FvExtHeader == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ if (*FfsCount >= 1) {
+ if ((memcmp(&CurrentFv->FfsAttuibutes[*FfsCount - 1].GuidName, &(LocalEncapDataTemp->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) {
+ memcpy(LocalEncapDataTemp->UiName, CurrentFv->FfsAttuibutes[*FfsCount - 1].UiName, _MAX_PATH);
+ LocalEncapDataTemp->UiNameSize = CurrentFv->FfsAttuibutes[*FfsCount - 1].UiNameSize;
+ LocalEncapDataTemp->DepexLen = CurrentFv->FfsAttuibutes[*FfsCount - 1].DepexLen;
+ LocalEncapDataTemp->Depex = malloc (LocalEncapDataTemp->DepexLen);
+ if (LocalEncapDataTemp->Depex == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ memcpy(LocalEncapDataTemp->Depex, CurrentFv->FfsAttuibutes[*FfsCount - 1].Depex, LocalEncapDataTemp->DepexLen);
+ }
+ }
+ }
+ break;
+ }
+ LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+ }
+
+ Status = LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag, TRUE);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "printing of FV section contents failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ if (*FfsCount >= 1) {
+ CurrentFv->FfsAttuibutes[*FfsCount -1].IsFvEnd = TRUE;
+ }
+ break;
+
+ case EFI_SECTION_COMPRESSION:
+ Level ++;
+ NumberOfSections ++;
+
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ EncapDataNeedUpdata = FALSE;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_COMPRESS_SECTION;
+
+ //
+ // Store the compress type
+ //
+ LocalEncapData->Data = malloc (sizeof (UINT8));
+
+ if (LocalEncapData->Data == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ } else {
+ LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+ if (LocalEncapData->RightNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData = LocalEncapData->RightNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_COMPRESS_SECTION;
+
+ //
+ // Store the compress type
+ //
+ LocalEncapData->Data = malloc (sizeof (UINT8));
+
+ if (LocalEncapData->Data == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+
+ }
+
+ //
+ // Process compressed section
+ //
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ UncompressedBuffer = NULL;
+ CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION) - LargeHeaderOffset;
+ UncompressedLength = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+ //printf (" Compression Type: EFI_NOT_COMPRESSED\n");
+ if (CompressedLength != UncompressedLength) {
+ Error ("FMMT", 0, 0, "file is not compressed, but the compressed length does not match the uncompressed length", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ GetInfoFunction = EfiGetInfo;
+ DecompressFunction = EfiDecompress;
+
+ CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+
+ Status = GetInfoFunction (CompressedBuffer, CompressedLength, &DstSize, &ScratchSize);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error getting compression info from compression section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ if (DstSize != UncompressedLength) {
+ Error ("FMMT", 0, 0003, "compression error in the compression section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ ScratchBuffer = malloc (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UncompressedBuffer = malloc (UncompressedLength);
+ if (UncompressedBuffer == NULL) {
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ free (ScratchBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Decompress the section.
+ //
+ Status = DecompressFunction (
+ CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ ScratchBuffer,
+ ScratchSize
+ );
+ free (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "decompress failed", NULL);
+ free (UncompressedBuffer);
+ return EFI_SECTION_ERROR;
+ }
+ } else {
+ Error ("FMMT", 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType);
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection ( UncompressedBuffer,
+ UncompressedLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated);
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ //
+ // We need to deallocate Buffer
+ //
+ free (UncompressedBuffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "failed to parse section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ //
+ // Process GUID defined
+ // looks up the appropriate tool to use for extracting
+ // a GUID defined FV section.
+ //
+ Level ++;
+ NumberOfSections++;
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ EncapDataNeedUpdata = FALSE;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+ GuidAttr = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->Attributes;
+ DataOffset = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->DataOffset;
+
+ if ((ViewFlag) && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0)) {
+ ToolOutputBuffer = Ptr + DataOffset;
+ ToolOutputLength = SectionLength - DataOffset;
+ Status = LibParseSection(
+ ToolOutputBuffer,
+ ToolOutputLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ break;
+ }
+
+ if (EncapDataNeedUpdata) {
+
+ //
+ // Put in this is an FFS with FV section
+ //
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_GUIDED_SECTION;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ // include DataOffset + Attributes
+ //
+
+ LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4);
+
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // include guid attribute and dataoffset
+ //
+ memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4);
+
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ } else {
+ LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+ if (LocalEncapData->RightNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData = LocalEncapData->RightNode;
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_GUIDED_SECTION;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ // include DataOffset + Attributes
+ //
+
+ LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4);
+
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // include guid attribute and dataoffset
+ //
+ memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4);
+
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ }
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid
+ );
+
+ if (ExtractionTool != NULL && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0)) {
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ free (ExtractionTool);
+ return EFI_SECTION_ERROR;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ ToolInputFile = GenTempFile ();
+ if (ToolInputFile == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (ExtractionTool);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolOutputFile = GenTempFile ();
+ if (ToolOutputFile == NULL) {
+ free (ToolInputFile);
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (ExtractionTool);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolInputFileName = strrchr(ToolInputFile, OS_SEP);
+ if (ToolInputFileName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+ ToolOutputFileName = strrchr(ToolOutputFile, OS_SEP);
+ if (ToolOutputFileName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+
+ ToolInputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolInputFileName) + 1);
+ if (ToolInputFileFullName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ExtractionTool);
+ Error ("FMMT", 0, 0003, "Allocate memory failed", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolOutputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolOutputFileName) + 1);
+
+ if (ToolOutputFileFullName == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolInputFileFullName);
+ free (ExtractionTool);
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName);
+ sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileName);
+
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "%s -d -o \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (ExtractionTool) +
+ strlen (ToolInputFileFullName) +
+ strlen (ToolOutputFileFullName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "%s -d -o \"%s\" \"%s\"",
+ ExtractionTool,
+ ToolOutputFileFullName,
+ ToolInputFileFullName
+ );
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+
+ Status = PutFileImage (
+ ToolInputFileFullName,
+ (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset
+ );
+
+ if (HasDepexSection) {
+ HasDepexSection = FALSE;
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "unable to decoded GUIDED section", NULL);
+ free (SystemCommand);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ remove (ToolInputFileFullName);
+ free (ToolInputFileFullName);
+ return EFI_SECTION_ERROR;
+ }
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ printf("Command failed: %s\n", SystemCommand);
+ free (SystemCommand);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ remove (ToolInputFileFullName);
+ free (ToolInputFileFullName);
+ return EFI_ABORTED;
+ }
+ free (SystemCommand);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ ToolInputFile = NULL;
+ ToolInputFileFullName = NULL;
+
+
+ Status = GetFileImage (
+ ToolOutputFileFullName,
+ (CHAR8 **)&ToolOutputBuffer,
+ &ToolOutputLength
+ );
+ remove (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ ToolOutputFile = NULL;
+ ToolOutputFileFullName = NULL;
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "unable to read decoded GUIDED section", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection (
+ ToolOutputBuffer,
+ ToolOutputLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ } else if ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0){
+ Status = LibParseSection (
+ Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ FfsLevel,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+ }else {
+ //
+ // We don't know how to parse it now.
+ //
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ Error ("FMMT", 0, 0003, "Error parsing section", \
+ "EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in %s file.", mGuidToolDefinition);
+ printf(" Its GUID is: ");
+ PrintGuid(&(((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->SectionDefinitionGuid));
+ return EFI_UNSUPPORTED;
+ }
+ break;
+
+ //
+ //Leaf sections
+ //
+ case EFI_SECTION_RAW:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PE32:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PIC:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_TE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_COMPATIBILITY16:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!*IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ *IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_VERSION:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ break;
+ case EFI_SECTION_PEI_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+ memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+ CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+ break;
+ case EFI_SECTION_DXE_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+ memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+ CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+ break;
+ case EFI_SECTION_SMM_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength);
+ memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength);
+ CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength;
+ break;
+
+ case EFI_SECTION_USER_INTERFACE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+ UiSectionLength = GetLength (((EFI_USER_INTERFACE_SECTION *) Ptr)->CommonHeader.Size);
+ if (UiSectionLength == 0xffffff) {
+ UiSectionLength = ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonHeader.ExtendedSize;
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER2);
+ } else {
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER);
+ }
+
+ UIName = (CHAR16 *) malloc (UINameSize + 2);
+ if (UIName != NULL) {
+ memset (UIName, '\0', UINameSize + 2);
+ if (UiSectionLength >= 0xffffff) {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameString, UINameSize);
+ } else {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UINameSize);
+ }
+ } else {
+ Error ("FMMT", 0, 0001, "Memory allocate error!", NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlankChar = LibConstructBlankChar( CurrentFv->FvLevel * 2);
+ if (BlankChar == NULL) {
+ free(UIName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (ViewFlag) {
+ UIFileName = malloc (UINameSize + 2);
+ if (UIFileName == NULL) {
+ Error ("FMMT", 0, 4001, "Memory allocation fail!", NULL);
+ free (UIName);
+ free (BlankChar);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Unicode2AsciiString (UIName, UIFileName);
+ fprintf(stdout, "%sFile \"%s\"\n", BlankChar, UIFileName);
+ free(UIFileName);
+ }
+ free (BlankChar);
+
+ //
+ // If Ffs file has been generated, then the FfsCount should decrease 1.
+ //
+ if (*IsFfsGenerated) {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UINameSize);
+ CurrentFv->FfsAttuibutes[*FfsCount -1].UiNameSize = UINameSize;
+ } else {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UINameSize);
+ CurrentFv->FfsAttuibutes[*FfsCount].UiNameSize = UINameSize;
+ }
+
+ HasDepexSection = FALSE;
+ free(UIName);
+ UINameSize = 0;
+
+ break;
+ default:
+ break;
+ }
+
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+
+ if (ParsedLength < BufferLength) {
+ Error ("FMMT", 0, 0003, "sections do not completely fill the sectioned buffer being parsed", NULL);
+ return EFI_SECTION_ERROR;
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Iterates through the files contained within the firmware volume
+
+ @param[in] Fv - Address of the Fv in memory
+ @param[in] Key - Should be 0 to get the first file. After that, it should be
+ passed back in without modifying it's contents to retrieve
+ subsequent files.
+ @param[in] File- Output file pointer
+ File == NULL - invalid parameter
+ otherwise - *File will be update to the location of the file
+
+ @return EFI_STATUS
+ EFI_NOT_FOUND
+ EFI_VOLUME_CORRUPTED
+
+**/
+EFI_STATUS
+FvBufFindNextFile (
+ IN VOID *Fv,
+ IN OUT UINTN *Key,
+ OUT VOID **File
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FFS_FILE_HEADER *fhdr;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN fsize;
+ EFI_STATUS Status;
+ UINTN fvSize;
+
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ fhdr = NULL;
+
+ if (Fv == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FvBufGetSize (Fv, &fvSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (*Key == 0) {
+ if (hdr->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)hdr + hdr->ExtHeaderOffset);
+ *Key = (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSize;
+ *Key = (UINTN)ALIGN_POINTER(*Key, 8);
+ } else {
+ *Key = hdr->HeaderLength;
+ }
+ }
+
+ FvbAttributes = hdr->Attributes;
+
+ for(
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8);
+ (*Key + sizeof (*fhdr)) < fvSize;
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8)
+ ) {
+ fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
+ fsize = GetFfsFileLength (fhdr);
+ if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_VALID
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_INVALID
+ )
+ ) {
+ *Key = *Key + 1;
+ continue;
+ } else if(
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_MARKED_FOR_UPDATE
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DELETED
+ )
+ ) {
+ *Key = *Key + fsize;
+ continue;
+ } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DATA_VALID
+ )
+ ) {
+ *File = (UINT8*)hdr + *Key;
+ *Key = *Key + fsize;
+ return EFI_SUCCESS;
+ }
+
+ *Key = *Key + 1;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ TODO: Add function description
+
+ FvImage - TODO: add argument description
+ FileHeader - TODO: add argument description
+ ErasePolarity - TODO: add argument description
+
+ EFI_SUCCESS - TODO: Add description for return value
+ EFI_ABORTED - TODO: Add description for return value
+
+**/
+EFI_STATUS
+LibGetFileInfo (
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ BOOLEAN ErasePolarity,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ ENCAP_INFO_DATA **CurrentFvEncapData,
+ UINT32 *FfsCount,
+ UINT8 *FvCount,
+ BOOLEAN ViewFlag
+ )
+{
+ UINT32 FileLength;
+ UINT8 FileState;
+ UINT8 Checksum;
+ EFI_FFS_FILE_HEADER2 BlankHeader;
+ EFI_STATUS Status;
+ UINT8 GuidBuffer[PRINTED_GUID_BUFFER_SIZE];
+ ENCAP_INFO_DATA *LocalEncapData;
+ BOOLEAN EncapDataNeedUpdateFlag;
+ BOOLEAN IsGeneratedFfs;
+ UINT32 FfsFileHeaderSize;
+
+ Status = EFI_SUCCESS;
+
+ LocalEncapData = NULL;
+ EncapDataNeedUpdateFlag = TRUE;
+ IsGeneratedFfs = FALSE;
+
+ FfsFileHeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FileLength = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ //
+ // Check if we have free space
+ //
+ if (ErasePolarity) {
+ memset (&BlankHeader, -1, FfsFileHeaderSize);
+ } else {
+ memset (&BlankHeader, 0, FfsFileHeaderSize);
+ }
+
+ //
+ // Is this FV blank?
+ //
+ if (memcmp (&BlankHeader, CurrentFile, FfsFileHeaderSize) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Print file information.
+ //
+ FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)CurrentFile);
+ PrintGuidToBuffer (&(CurrentFile->Name), GuidBuffer, PRINTED_GUID_BUFFER_SIZE, FALSE);
+ if (FileState == EFI_FILE_DATA_VALID) {
+ //
+ // Calculate header checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize);
+ Checksum = (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum.File);
+ Checksum = (UINT8) (Checksum - CurrentFile->State);
+ if (Checksum != 0) {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum", GuidBuffer);
+ return EFI_ABORTED;
+ }
+
+ if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ //
+ // Calculate file checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFileHeaderSize), FileLength - FfsFileHeaderSize);
+ Checksum = Checksum + CurrentFile->IntegrityCheck.Checksum.File;
+ if (Checksum != 0) {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid file checksum", GuidBuffer);
+ return EFI_ABORTED;
+ }
+ } else {
+ if (CurrentFile->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum -- not set to fixed value of 0xAA", GuidBuffer);
+ return EFI_ABORTED;
+ }
+ }
+ } else {
+ Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has the invalid/unrecognized file state bits", GuidBuffer);
+ return EFI_ABORTED;
+ }
+
+ Level += 1;
+
+ if ((CurrentFile->Type != EFI_FV_FILETYPE_ALL) && (CurrentFile->Type != EFI_FV_FILETYPE_FFS_PAD)) {
+
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ EncapDataNeedUpdateFlag = FALSE;
+ while (LocalEncapData->RightNode != NULL) {
+ LocalEncapData = LocalEncapData->RightNode;
+ }
+ }
+
+ if (EncapDataNeedUpdateFlag) {
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FFS;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // Store the header of FFS file.
+ //
+ LocalEncapData->Data = malloc (FfsFileHeaderSize);
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1;
+ LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2;
+ LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3;
+ LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0];
+ LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1];
+ LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2];
+ LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3];
+ LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4];
+ LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5];
+ LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6];
+ LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7];
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+ }else{
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->RightNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->RightNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FFS;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ //
+ // Store the header of FFS file.
+ //
+ LocalEncapData->Data = malloc (FfsFileHeaderSize);
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1;
+ LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2;
+ LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3;
+ LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0];
+ LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1];
+ LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2];
+ LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3];
+ LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4];
+ LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5];
+ LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6];
+ LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7];
+ LocalEncapData->RightNode = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ if ( CurrentFile->Type == EFI_FV_FILETYPE_RAW){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag){
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ } else if( CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD){
+ //EFI_FV_FILETYPE_FFS_PAD
+ } else {
+ //
+ // All other files have sections
+ //
+ Status = LibParseSection (
+ (UINT8 *) ((UINTN) CurrentFile + FfsFileHeaderSize),
+ FileLength - FfsFileHeaderSize,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ &LocalEncapData,
+ Level,
+ FfsCount,
+ FvCount,
+ ViewFlag,
+ ErasePolarity,
+ &IsGeneratedFfs
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ printf ("ERROR: Parsing the FFS file.\n");
+ return Status;
+ }
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get firmware information. Including the FV headers,
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN ENCAP_INFO_DATA **CurrentFvEncapData,
+ IN UINT32 *FfsCount,
+ IN OUT UINT8 *FvCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfFiles;
+ BOOLEAN ErasePolarity;
+ UINTN FvSize;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ UINTN Key;
+ ENCAP_INFO_DATA *LocalEncapData;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHdrPtr;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHdr;
+
+ NumberOfFiles = 0;
+ Key = 0;
+ LocalEncapData = NULL;
+ CurrentFile = NULL;
+ FvHdr = (EFI_FIRMWARE_VOLUME_HEADER *)Fv;
+
+
+ Level += 1;
+ *FvCount += 1;
+ CurrentFv->FvLevel += 1;
+
+ Status = FvBufGetSize (Fv, &FvSize);
+
+ ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE;
+
+ Status = LibReadFvHeader (Fv, ViewFlag, CurrentFv->FvLevel, *FvCount - 1, CurrentFv->FvName);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error parsing FV image", "Header is invalid");
+ return EFI_ABORTED;
+ }
+
+ if (!IsChildFv) {
+ //
+ // Write FV header information into CurrentFv struct.
+ //
+ CurrentFv->FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvHdr->HeaderLength);
+
+ if (CurrentFv->FvHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV Header information
+ //
+ memcpy(CurrentFv->FvHeader, Fv, FvHdr->HeaderLength);
+ CurrentFv->FvExtHeader = NULL;
+ CurrentFv->FvUiName = NULL;
+
+ //
+ // Exist Extend FV header.
+ //
+ if (CurrentFv->FvHeader->ExtHeaderOffset != 0){
+ ExtHdrPtr = (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset);
+ CurrentFv->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+ if (CurrentFv->FvExtHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy (CurrentFv->FvExtHeader, (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ LibExtractFvUiName(CurrentFv->FvExtHeader, &CurrentFv->FvUiName);
+ }
+ }
+
+ //
+ // Put encapsulate information into structure.
+ //
+ LocalEncapData = *CurrentFvEncapData;
+ if (LocalEncapData == NULL && !IsChildFv) {
+ //
+ // First time in, the root FV
+ //
+ LocalEncapData = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+ CurrentFv->EncapData = LocalEncapData;
+ if (CurrentFv->EncapData == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ CurrentFv->EncapData->FvExtHeader = NULL;
+ CurrentFv->EncapData->Depex = NULL;
+ CurrentFv->EncapData->DepexLen = 0;
+ CurrentFv->EncapData->UiNameSize = 0;
+ CurrentFv->EncapData->Level = Level;
+ CurrentFv->EncapData->Type = FMMT_ENCAP_TREE_FV;
+ CurrentFv->EncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ CurrentFv->EncapData->FvId = *FvCount;
+
+ if (CurrentFv->EncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset);
+ CurrentFv->EncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+ if (CurrentFv->EncapData->FvExtHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(CurrentFv->EncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ }
+
+ CurrentFv->EncapData->NextNode = NULL;
+ CurrentFv->EncapData->RightNode = NULL;
+ } else if (LocalEncapData == NULL) {
+ return EFI_ABORTED;
+ } else if (IsChildFv) {
+
+ LocalEncapData = *CurrentFvEncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = FMMT_ENCAP_TREE_FV;
+ LocalEncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->Depex = NULL;
+ LocalEncapData->DepexLen = 0;
+ LocalEncapData->UiNameSize = 0;
+ LocalEncapData->FvId = *FvCount;
+ if (LocalEncapData->Data == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(ExtHdrPtr->ExtHeaderSize);
+
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(LocalEncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ }
+
+ LocalEncapData->NextNode = NULL;
+ LocalEncapData->RightNode = NULL;
+
+ }
+
+
+ //
+ // Get the first file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the first file in the FV image");
+ return Status;
+ }
+
+ while (CurrentFile != NULL) {
+
+ //
+ // Increment the number of files counter
+ //
+ NumberOfFiles++;
+
+ //
+ // Store FFS file Header information
+ //
+ CurrentFv->FfsHeader[*FfsCount].Attributes = CurrentFile->Attributes;
+ CurrentFv->FfsHeader[*FfsCount].IntegrityCheck = CurrentFile->IntegrityCheck;
+ CurrentFv->FfsHeader[*FfsCount].Name = CurrentFile->Name;
+ CurrentFv->FfsHeader[*FfsCount].Size[0] = CurrentFile->Size[0];
+ CurrentFv->FfsHeader[*FfsCount].Size[1] = CurrentFile->Size[1];
+ CurrentFv->FfsHeader[*FfsCount].Size[2] = CurrentFile->Size[2];
+ CurrentFv->FfsHeader[*FfsCount].State = CurrentFile->State;
+ CurrentFv->FfsHeader[*FfsCount].Type = CurrentFile->Type;
+ CurrentFv->FfsHeader[*FfsCount].ExtendedSize = CurrentFile->ExtendedSize;
+ CurrentFv->FfsAttuibutes[*FfsCount].Offset = Key - GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ CurrentFv->FfsAttuibutes[*FfsCount].FvLevel = CurrentFv->FvLevel;
+ if (CurrentFv->FvLevel > CurrentFv->MulFvLevel) {
+ CurrentFv->MulFvLevel = CurrentFv->FvLevel;
+ }
+ //
+ // Display info about this file
+ //
+ Status = LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag);
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error parsing FV image", "failed to parse a file in the FV");
+ return Status;
+ }
+
+ //
+ // Get the next file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the next file in the FV image");
+ return Status;
+ }
+ }
+
+ if (IsChildFv) {
+ if (CurrentFv->FvLevel > 1) {
+ CurrentFv->FvLevel -= 1;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ )
+{
+ UINT32 OccupiedSize;
+
+ OccupiedSize = ActualSize;
+ while ((OccupiedSize & (Alignment - 1)) != 0) {
+ OccupiedSize++;
+ }
+
+ return OccupiedSize;
+}
+
+
+
+EFI_STATUS
+LibDeleteAndRenameFfs(
+ IN CHAR8* DeleteFile,
+ IN CHAR8* NewFile
+)
+{
+ CHAR8* SystemCommand;
+ CHAR8* TemDir;
+ SystemCommand = NULL;
+
+ if (DeleteFile == NULL ||
+ NewFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete the file of the specified extract FFS file.
+ //
+ SystemCommand = malloc (
+ strlen (DEL_STR) +
+ strlen (DeleteFile) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ DEL_STR,
+ DeleteFile
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
+
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ //
+ // Create a copy the new file.
+ //
+
+ SystemCommand = malloc (
+ strlen (COPY_STR) +
+ strlen (NewFile) +
+ strlen (DeleteFile) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ COPY_STR,
+ NewFile,
+ DeleteFile
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Converts ASCII characters to Unicode.
+ Assumes that the Unicode characters are only these defined in the ASCII set.
+
+ String - Pointer to string that is written to FILE.
+ UniString - Pointer to unicode string
+
+ The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+ IN CHAR8 *String,
+ OUT CHAR16 *UniString
+ )
+{
+ while (*String != '\0') {
+ *(UniString++) = (CHAR16) *(String++);
+ }
+ //
+ // End the UniString with a NULL.
+ //
+ *UniString = '\0';
+}
+
+
+EFI_STATUS
+LibCreateGuidedSectionOriginalData(
+ IN CHAR8* FileIn,
+ IN CHAR8* ToolName,
+ IN CHAR8* FileOut
+)
+{
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+
+ if (FileIn == NULL ||
+ ToolName == NULL ||
+ FileOut == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete the file of the specified extract FFS file.
+ //
+ SystemCommandFormatString = "%s -e \"%s\" -o \"%s\"";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (FileIn) +
+ strlen (ToolName) +
+ strlen (FileOut) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ "%s -e \"%s\" -o \"%s\"",
+ ToolName,
+ FileIn,
+ FileOut
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ printf("Command failed: %s\n", SystemCommand);
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function convert the FV header's attribute to a string. The converted string
+ will be put into an INF file as the input of GenFV.
+
+ @param[in] Attr FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+ @retval EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+LibFvHeaderAttributeToStr (
+ IN EFI_FVB_ATTRIBUTES_2 Attr,
+ IN FILE* InfFile
+)
+{
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ LocalStr = (CHAR8 *) malloc (1024 * 4);
+
+ if (LocalStr == NULL) {
+ printf ("Memory allocate error!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', 1024 * 4);
+
+ if (Attr == 0 || InfFile == NULL) {
+ free (LocalStr);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ strncat (LocalStr, "[attributes] \n", sizeof("[attributes] \n"));
+
+ if (Attr & EFI_FVB2_READ_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_DISABLED_CAP = TRUE \n", sizeof ("EFI_READ_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_ENABLED_CAP = TRUE \n", sizeof ("EFI_READ_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_STATUS) {
+ strncat (LocalStr, "EFI_READ_STATUS = TRUE \n", sizeof ("EFI_READ_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_DISABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_ENABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_STATUS = TRUE \n", sizeof ("EFI_WRITE_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_CAP) {
+ strncat (LocalStr, "EFI_LOCK_CAP = TRUE \n", sizeof ("EFI_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_LOCK_STATUS = TRUE \n", sizeof ("EFI_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_STICKY_WRITE) {
+ strncat (LocalStr, "EFI_STICKY_WRITE = TRUE \n", sizeof ("EFI_STICKY_WRITE = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_MEMORY_MAPPED) {
+ strncat (LocalStr, "EFI_MEMORY_MAPPED = TRUE \n", sizeof ("EFI_MEMORY_MAPPED = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_ERASE_POLARITY) {
+ strncat (LocalStr, "EFI_ERASE_POLARITY = 1 \n", sizeof ("EFI_ERASE_POLARITY = 1 \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_CAP) {
+ strncat (LocalStr, "EFI_READ_LOCK_CAP = TRUE \n", sizeof ("EFI_READ_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_CAP) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_CAP = TRUE \n", sizeof ("EFI_WRITE_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_STATUS = TRUE \n", sizeof ("EFI_WRITE_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ //
+ // Alignment
+ //
+ if (Attr & EFI_FVB2_ALIGNMENT_1) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1G = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2G = TRUE \n"));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while writing data to %p file.", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] BlockMap FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibFvHeaderOptionToStr (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
+ IN FILE* InfFile,
+ IN BOOLEAN IsRootFv
+)
+{
+ CHAR8 *LocalStr;
+ CHAR8 *TempStr;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+
+ LocalStr = NULL;
+ TempStr = NULL;
+
+ if (FvHeader == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // This section will not over 1024 bytes and each line will never over 128 bytes.
+ //
+ LocalStr = (CHAR8 *) malloc (1024);
+ TempStr = (CHAR8 *) malloc (128);
+
+ if (LocalStr == NULL ||
+ TempStr == NULL ) {
+ if (LocalStr != NULL) {
+ free (LocalStr);
+ }
+ if (TempStr != NULL) {
+ free (TempStr);
+ }
+ printf ("Memory allocate error! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlockMap = FvHeader->BlockMap;
+ memset (LocalStr, '\0', 1024);
+ memset (TempStr, '\0', 128);
+
+ strncat (LocalStr, "[options] \n", sizeof("[Options] \n"));
+
+
+ snprintf (TempStr, 128, "EFI_BLOCK_SIZE = 0x%x \n", BlockMap->Length);
+ strncat (LocalStr, TempStr, strlen(TempStr));
+
+ if (IsRootFv) {
+ snprintf (TempStr, 128, "EFI_NUM_BLOCKS = 0x%x \n", BlockMap->NumBlocks);
+ strncat (LocalStr, TempStr, strlen(TempStr));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while writing data to %p file.", (void*)InfFile);
+ free (LocalStr);
+ free (TempStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+ free (TempStr);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] FfsName Ffs file path/name.
+ @param[out] InfFile InfFile contain FV header attribute information
+ @param[in] FirstIn Is the first time call this function? If yes, should create [files] section.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibAddFfsFileToFvInf (
+ IN CHAR8 *FfsName,
+ IN FILE* InfFile,
+ IN BOOLEAN FirstIn
+)
+{
+
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ if (FfsName == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (strlen(FfsName) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ LocalStr = (CHAR8 *) malloc (_MAX_PATH);
+
+ if (LocalStr == NULL) {
+ printf ("Memory allocate error! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', _MAX_PATH);
+
+ if (FirstIn) {
+ sprintf (LocalStr, "[files] \nEFI_FILE_NAME = %s \n", FfsName);
+ } else {
+ sprintf (LocalStr, "EFI_FILE_NAME = %s \n", FfsName);
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while writing data to %p file.", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Convert EFI file to PE or TE section
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] Type PE or TE and UI/Version
+ @param[in] OutputFilePath .te or .pe file
+ @param[in] UiString String for generate UI section usage, this parameter is optional
+ unless Type is EFI_SECTION_USER_INTERFACE.
+ @param[in] VerString String for generate Version section usage, this parameter is optional
+ unless Type is EFI_SECTION_VERSION.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibCreateFfsSection (
+ IN FV_INFORMATION *FvInFd, OPTIONAL
+ IN CHAR8* InputFilePath, OPTIONAL
+ IN CHAR8* Sections, OPTIONAL
+ IN UINT8 Type,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* UiString, OPTIONAL
+ IN CHAR8* VerString, OPTIONAL
+ IN CHAR8* GuidToolGuid, OPTIONAL
+ IN UINT16 GuidHeaderLength,
+ IN UINT16 GuidAttr,
+ IN CHAR8* CompressType OPTIONAL
+ )
+{
+ //EFI_STATUS Status;
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ FILE *file;
+ UINT8 Buffer[4];
+ int BitNum;
+ int Position;
+ UINT32 AlignmentValue;
+ //
+ // Workaround for static code checkers.
+ // Ensures the size of 'AlignmentStr' can hold all the digits of an
+ // unsigned 32-bit integer plus the size unit character.
+ //
+ char AlignmentStr[16];
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ strcpy(AlignmentStr,"1");
+ //
+ // Call GenSec tool to generate FFS section.
+ //
+
+ //
+ // -s SectionType.
+ //
+ if (Type != 0) {
+ switch (Type) {
+ //
+ // Process compression section
+ //
+ case EFI_SECTION_COMPRESSION:
+ SystemCommandFormatString = "GenSec -s %s -c %s \"%s\" -o \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (CompressType) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec -s %s -c %s \"%s\" -o \"%s\"",
+ mSectionTypeName[Type],
+ CompressType,
+ InputFilePath,
+ OutputFilePath
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ //
+ // Process GUID defined section
+ //
+ case EFI_SECTION_GUID_DEFINED:
+ SystemCommandFormatString = "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (GuidToolGuid) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ strlen (mGuidSectionAttr[GuidAttr&0x01]) +
+ strlen (mGuidSectionAttr[GuidAttr&0x02]) +
+ 4 +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d",
+ mSectionTypeName[Type],
+ GuidToolGuid,
+ InputFilePath,
+ OutputFilePath,
+ mGuidSectionAttr[GuidAttr&0x01],
+ mGuidSectionAttr[GuidAttr&0x02],
+ GuidHeaderLength
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+
+ SystemCommandFormatString = "GenSec -s %s \"%s\" -o \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec -s %s \"%s\" -o \"%s\"",
+ mSectionTypeName[Type],
+ InputFilePath,
+ OutputFilePath
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ default:
+ Error ("FMMT", 0, 0003, "Please specify the section type while call GenSec tool.", NULL);
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ //
+ // Create Dummy section.
+ //
+ file = fopen(InputFilePath, "rb");
+ if (file == NULL) {
+ Error(NULL, 0, 0001, "Error opening the file", InputFilePath);
+ return EFI_INVALID_PARAMETER;
+ }
+ // The Section Struct, 3 bits for Size, then 1 bit for Type
+ if (fread(Buffer, 1, (size_t)(4), file) != (size_t)(4)) {
+ fclose(file);
+ return EFI_ABORTED;
+ }
+ if (*(Buffer + 3) == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
+ // The Section Struct, if size is not 0xFFFF, the length is 4
+ Position = 4;
+ // If Size is 0xFFFFFF then ExtendedSize contains the size of the section
+ if ((*Buffer == 0xFF) && (*(Buffer + 1) == 0xFF) && (*(Buffer + 2) == 0xFF)) {
+ Position = 8;
+ }
+ //Per EFI_FIRMWARE_VOLUME_HEADER struct, 0x2E bit is EFI_FVB_ATTRIBUTES_2 attr
+ fseek(file, 0x2E + Position, SEEK_SET);
+ BitNum = fgetc(file);
+ AlignmentValue = 1 << (BitNum & 0x1F);
+ if (AlignmentValue >= 0x400){
+ if (AlignmentValue >= 0x10000){
+ strcpy(AlignmentStr,"64K");
+ }
+ else{
+ sprintf(AlignmentStr, "%d", AlignmentValue/0x400);
+ strcat(AlignmentStr, "K");
+ }
+ }
+ else{
+ sprintf(AlignmentStr, "%d", AlignmentValue);
+ }
+ strcpy(FvInFd->AlignmentStr, AlignmentStr);
+ }
+ fclose(file);
+ SystemCommandFormatString = "GenSec \"%s\" -o \"%s\" --sectionalign %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 4 + // Alignment maximum length
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenSec \"%s\" -o \"%s\" --sectionalign %s",
+ InputFilePath,
+ OutputFilePath,
+ AlignmentStr
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Encapsulate FFSs to FV
+
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] BlockSize BlockSize is one HEX or DEC format value required by FV image.
+ @param[in] FileTakeSize
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapsulateFfsToFv (
+ IN CHAR8* InfFilePath,
+ IN CHAR8* InputFFSs,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* FvGuidName,
+ IN BOOLEAN IsLargeFile
+ )
+{
+
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ CHAR8* FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3";
+
+ if (IsLargeFile == TRUE) {
+ FfsGuid = "5473c07a-3dcb-4dca-bd6f-1e9689e7349a";
+ }
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+
+ if (OutputFilePath == NULL ||
+ InfFilePath == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InfFilePath != NULL) {
+ if (FvGuidName == NULL) {
+ SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\"";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (InfFilePath) +
+ strlen (FfsGuid) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFv -i \"%s\" -g %s -o \"%s\"",
+ InfFilePath, // -i
+ FfsGuid, // -g
+ OutputFilePath // -o
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+
+ free(SystemCommand);
+ } else {
+ //
+ // Have FvGuidName in it.
+ //
+ SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (InfFilePath) +
+ strlen (FfsGuid) +
+ strlen (OutputFilePath) +
+ strlen (FvGuidName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s",
+ InfFilePath, // -i
+ FfsGuid, // -g
+ OutputFilePath, // -o
+ FvGuidName // FvNameGuid
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Convert a GUID to a string.
+
+
+ @param[in] Guid - Pointer to GUID to print.
+
+
+ @return The string after convert.
+
+**/
+CHAR8 *
+LibFmmtGuidToStr (
+ IN EFI_GUID *Guid
+)
+{
+ CHAR8 * Buffer;
+
+ Buffer = NULL;
+
+ if (Guid == NULL) {
+ printf ("The guid is NULL while convert guid to string! \n");
+ return NULL;
+ }
+
+ Buffer = (CHAR8 *) malloc (36 + 1);
+
+ if (Buffer == NULL) {
+ printf ("Error while allocate resource! \n");
+ return NULL;
+ }
+ memset (Buffer, '\0', 36 + 1);
+
+ sprintf (
+ Buffer,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ Guid->Data1,
+ Guid->Data2,
+ Guid->Data3,
+ Guid->Data4[0],
+ Guid->Data4[1],
+ Guid->Data4[2],
+ Guid->Data4[3],
+ Guid->Data4[4],
+ Guid->Data4[5],
+ Guid->Data4[6],
+ Guid->Data4[7]
+ );
+
+ return Buffer;
+}
+
+
+/**
+ Encapsulate an FFS section file to an FFS file.
+
+ @param[in] Type Type is one FV file type defined in PI spec, which is one type of EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,
+ EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,
+ EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION, EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE. This option is required.
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] FileGuid FileGuid is the unique identifier for this FFS file. This option is required.
+ @param[in] Fixed Set fixed attribute in FFS file header to indicate that the file may not be moved from its present location.
+ @param[in] SectionAlign FileAlign specifies FFS file alignment, which only support the following alignment: 8,16,128,512,1K,4K,32K,64K.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapSectionFileToFFS (
+ IN UINT8 Type,
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath,
+ IN EFI_GUID FileGuid,
+ IN BOOLEAN Fixed,
+ IN CHAR8* SectionAlign
+ )
+{
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ CHAR8* GuidStr;
+
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ GuidStr = NULL;
+
+ GuidStr = LibFmmtGuidToStr(&FileGuid);
+
+ if (GuidStr == NULL) {
+ return EFI_ABORTED;
+ }
+
+
+ //
+ // -t Type
+ // -i InputFilePath
+ // -o OutPutFilePath
+ // -g FileGuid
+ // -x Fixed
+ // -n SectionAlign
+ //
+
+ if (Fixed) {
+ SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 4 +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s",
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath, // -o
+ SectionAlign
+ );
+
+ free (GuidStr);
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ } else {
+ SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 4 +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (GuidStr);
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s",
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath, // -o
+ SectionAlign
+ );
+
+ free (GuidStr);
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibCreateNewFdCopy(
+ IN CHAR8* OldFd,
+ IN CHAR8* NewFd
+)
+{
+
+ FILE* NewFdFile;
+ FILE* OldFdFile;
+ CHAR8 *NewFdDir;
+ CHAR8 *OldFdDir;
+ UINT64 FdLength;
+ UINT32 Count;
+ BOOLEAN UseNewDirFlag;
+ CHAR8 *Buffer;
+
+ NewFdFile = NULL;
+ OldFdFile = NULL;
+ NewFdDir = NULL;
+ OldFdDir = NULL;
+ Count = 0;
+ UseNewDirFlag = FALSE;
+
+ if (OldFd == NULL ||
+ NewFd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ NewFdDir = getcwd (NULL, _MAX_PATH);
+
+ Count = strlen(NewFdDir);
+
+ if (strlen(NewFd) > Count) {
+
+ do {
+ if (NewFdDir[Count-1] == NewFd[Count-1]) {
+ Count--;
+ } else {
+ if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) {
+ return EFI_ABORTED;
+ }
+ strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1);
+ strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1);
+ UseNewDirFlag = TRUE;
+ break;
+ }
+
+ } while (Count != 1);
+
+ }else {
+ if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) {
+ return EFI_ABORTED;
+ }
+ strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1);
+ strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1);
+ UseNewDirFlag = TRUE;
+ }
+
+ if (UseNewDirFlag) {
+ NewFdFile = fopen (NewFdDir, "wb+");
+ if (NewFdFile == NULL) {
+ NewFdFile = fopen (NewFd, "wb+");
+ }
+ } else {
+ NewFdFile = fopen (NewFd, "wb+");
+ }
+ // support network path file
+ if (OldFd[0] == '\\' && OldFd[1] == '\\') {
+ OldFdFile = fopen (OldFd, "rb");
+ } else {
+ UseNewDirFlag = FALSE;
+
+ OldFdDir = getcwd (NULL, _MAX_PATH);
+
+ Count = strlen(OldFdDir);
+
+ if (strlen(OldFd) > Count) {
+
+ do {
+ if (OldFdDir[Count-1] == OldFd[Count-1]) {
+ Count--;
+ } else {
+ if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) {
+ if (NewFdFile != NULL) {
+ fclose(NewFdFile);
+ }
+ return EFI_ABORTED;
+ }
+ strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1);
+ strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1);
+ UseNewDirFlag = TRUE;
+ break;
+ }
+
+ } while (Count != 1);
+
+ }else {
+ if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) {
+ if (NewFdFile != NULL) {
+ fclose(NewFdFile);
+ }
+ return EFI_ABORTED;
+ }
+ strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1);
+ strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1);
+ UseNewDirFlag = TRUE;
+ }
+
+ if (UseNewDirFlag) {
+ OldFdFile = fopen (OldFdDir, "rb+");
+ if (OldFdFile == NULL) {
+ OldFdFile = fopen (OldFd, "rb+");
+ }
+ } else {
+ OldFdFile = fopen (OldFd, "rb+");
+ }
+ }
+
+ if (NewFdFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file.");
+ if (OldFdFile != NULL) {
+ fclose (OldFdFile);
+ }
+ return EFI_ABORTED;
+ }
+
+ if (OldFdFile == NULL) {
+ Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file.");
+ if (NewFdFile != NULL) {
+ fclose (NewFdFile);
+ }
+ return EFI_ABORTED;
+ }
+
+
+ fseek(OldFdFile,0,SEEK_SET);
+ fseek(OldFdFile,0,SEEK_END);
+
+ FdLength = ftell(OldFdFile);
+
+ fseek(OldFdFile,0,SEEK_SET);
+ fseek(NewFdFile,0,SEEK_SET);
+
+ Buffer = malloc ((size_t)FdLength);
+
+ if (Buffer == NULL) {
+ fclose(OldFdFile);
+ fclose(NewFdFile);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) FdLength, OldFdFile) != (size_t) FdLength) {
+ Error ("FMMT", 0, 0003, "error reading FD file %s", OldFd);
+ free (Buffer);
+ fclose(OldFdFile);
+ fclose(NewFdFile);
+ return EFI_ABORTED;
+ }
+
+ if (fwrite (Buffer, 1, (size_t) FdLength, NewFdFile) != (size_t) FdLength) {
+ Error ("FMMT", 0, 0004, "error writing FD file", "cannot Create a new FD file.");
+ free (Buffer);
+ fclose(OldFdFile);
+ fclose(NewFdFile);
+ return EFI_ABORTED;
+ }
+ free (Buffer);
+ fclose(OldFdFile);
+ fclose (NewFdFile);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will assemble the filename, directory and extend and return the combined string.
+ Like FileName = file1, Dir = c:\temp extend = txt, the output string will be:
+ c:\temp\file1.txt.
+
+ @param[in]
+ @param[in]
+ @param[in]
+
+ @retrun A string contain all the input information.
+
+**/
+CHAR8 *
+LibFilenameStrExtended (
+ IN CHAR8 *FileName,
+ IN CHAR8 *Dir,
+ IN CHAR8 *Extend
+)
+{
+ CHAR8 *RetStr;
+
+ RetStr = NULL;
+
+ if (FileName == NULL) {
+ return NULL;
+ }
+
+ if (Dir == NULL || Extend == NULL) {
+ return FileName;
+ }
+
+ RetStr = (CHAR8 *) malloc (strlen (FileName) +
+ strlen (Dir) +
+ strlen (Extend) +
+ strlen ("%s%s.%s") +
+ 1);
+ if (RetStr == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return NULL;
+ }
+
+ memset (RetStr, '\0', (strlen (FileName) + strlen (Dir) + strlen (Extend) + strlen ("%s%s.%s") + 1));
+
+ sprintf (RetStr, "%s%s.%s", Dir, FileName, Extend);
+
+ return RetStr;
+}
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+
+ if (DirName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (access (DirName, 0) == -1){
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Delete a directory and files in it.
+ //
+
+ SystemCommand = malloc (
+ strlen (RMDIR_STR) +
+ strlen (DirName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ RMDIR_STR,
+ DirName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibGenExtFile(
+CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtPtr,
+FILE *InfFile
+)
+{
+ CHAR8 *TempDir;
+ FILE *ExtFile;
+ CHAR8 OutputExtFile[_MAX_PATH];
+ CHAR8 Line[512];
+ size_t Len;
+
+ TempDir = NULL;
+
+ TempDir = getcwd(NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) -1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) -1);
+
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ sprintf(
+ Line,
+ "%c%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X%d.ext",
+ OS_SEP,
+ (unsigned)ExtPtr->FvName.Data1,
+ ExtPtr->FvName.Data2,
+ ExtPtr->FvName.Data3,
+ ExtPtr->FvName.Data4[0],
+ ExtPtr->FvName.Data4[1],
+ ExtPtr->FvName.Data4[2],
+ ExtPtr->FvName.Data4[3],
+ ExtPtr->FvName.Data4[4],
+ ExtPtr->FvName.Data4[5],
+ ExtPtr->FvName.Data4[6],
+ ExtPtr->FvName.Data4[7],
+ ExtPtr->ExtHeaderSize
+ );
+ if (strlen (TempDir) + strlen (Line) > _MAX_PATH - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncpy (OutputExtFile, TempDir, _MAX_PATH - 1);
+ OutputExtFile[_MAX_PATH - 1] = 0;
+ strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1);
+
+
+ ExtFile = fopen(OutputExtFile, "wb+");
+ if (ExtFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) != ExtPtr->ExtHeaderSize) {
+ fclose(ExtFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(ExtFile);
+
+ strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME = ");
+ if (strlen (Line) + strlen (OutputExtFile) + 1 > sizeof(Line) / sizeof (CHAR8) - 1) {
+ Error("FMMT", 0, 1001, "The directory is too long.", "");
+ return EFI_ABORTED;
+ }
+ strncat (Line, OutputExtFile, sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ Len = strlen(Line);
+ if (fwrite(Line, 1, Len, InfFile) != Len) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a file.
+
+ @param[in] FileName Name of the file need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibFmmtDeleteFile(
+ IN CHAR8 *FileName
+)
+{
+ CHAR8* SystemCommand;
+ CHAR8 *TemDir;
+
+ SystemCommand = NULL;
+ TemDir = NULL;
+
+
+ if (FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // if the FileName is not in TemDir, we don't need to delete.
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (*(TemDir + strlen(TemDir) - 1) == OS_SEP) {
+ *(TemDir + strlen(TemDir) - 1) = '\0';
+ }
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ Error (NULL, 0, 2000, "Path: The current path is too long.", NULL);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ if (strstr(FileName, TemDir) == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Delete a file
+ //
+
+ SystemCommand = malloc (
+ strlen (DEL_STR) +
+ strlen (FileName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ DEL_STR,
+ FileName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibFmmtFreeFd (
+ FIRMWARE_DEVICE *Fd
+ )
+{
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *TempFv;
+ ENCAP_INFO_DATA *EncapData1;
+ ENCAP_INFO_DATA *EncapData2;
+
+ CurrentFv = NULL;
+ TempFv = NULL;
+ EncapData1 = NULL;
+ EncapData2 = NULL;
+
+ if (Fd == NULL) {
+ return;
+ }
+
+ CurrentFv = Fd->Fv;
+
+ do {
+ TempFv = CurrentFv;
+ CurrentFv = CurrentFv->FvNext;
+
+ free (TempFv->FvHeader);
+
+ if (TempFv->FvExtHeader != NULL) {
+ free (TempFv->FvExtHeader);
+ }
+ if (TempFv->FvUiName) {
+ free(TempFv->FvUiName);
+ }
+
+ //
+ // Free encapsulate data;
+ //
+ EncapData1 = TempFv->EncapData;
+
+ while (EncapData1 != NULL) {
+
+ EncapData2 = EncapData1;
+ EncapData1 = EncapData1->NextNode;
+
+ if (EncapData2->Data != NULL) {
+ free (EncapData2->Data);
+ }
+ if (EncapData2->FvExtHeader != NULL) {
+ free(EncapData2->FvExtHeader);
+ }
+ free (EncapData2);
+ EncapData2 = NULL;
+ }
+
+ EncapData1 = NULL;
+
+ free (TempFv);
+ TempFv = NULL;
+
+ } while (CurrentFv != NULL);
+
+ CurrentFv = NULL;
+ free (Fd);
+ Fd = NULL;
+
+ return;
+}
+
+/**
+ Generate the compressed section with specific type.
+ Type could be EFI_STANDARD_COMPRESSION or EFI_NOT_COMPRESSED
+
+ @param[in] InputFileName File name of the raw data.
+ @param[in] OutPutFileName File name of the sectioned data.
+ @param[in] CompressionType The compression type.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_ABORTED
+ @return EFI_OUT_OF_RESOURCES
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibGenCompressedSection (
+ CHAR8 *InputFileName,
+ CHAR8 *OutPutFileName,
+ UINT8 CompressionType
+)
+{
+ //FILE *UnCompressFile;
+ //FILE *CompressedFile;
+ //VOID *UnCompressedBuffer;
+ //VOID *CompressedBuffer;
+ //UINT32 UnCompressedSize;
+ //UINT32 CompressedSize;
+ //CHAR8 *TempName;
+ //CHAR8 *TemDir;
+ //EFI_STATUS Status;
+
+ //UnCompressFile = NULL;
+ //CompressedFile = NULL;
+ //UnCompressedBuffer = NULL;
+ //CompressedBuffer = NULL;
+ //TempName = NULL;
+ //TemDir = NULL;
+ //UnCompressedSize = 0;
+ //CompressedSize = 0;
+
+ if ( InputFileName == NULL ||
+ OutPutFileName == NULL) {
+ printf ("Error while generate compressed section!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ /*
+
+ UnCompressFile = fopen (InputFileName, "rb");
+ if (UnCompressFile == NULL) {
+ printf ("Error while open file %s \n", InputFileName);
+ return EFI_ABORTED;
+ }
+
+ TemDir = _getcwd (NULL, _MAX_PATH);
+ sprintf(TemDir, "%s\\%s", TemDir, TEMP_DIR_NAME);
+
+ TempName= LibFilenameStrExtended (strrchr(CloneString (tmpnam (NULL)),'\\'), TemDir, "comp");
+
+ CompressedFile = fopen (TempName, "wb+");
+ if (CompressedFile == NULL) {
+ printf ("Error while open file %s \n", TempName);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the original file size;
+ //
+ fseek(UnCompressFile,0,SEEK_SET);
+ fseek(UnCompressFile,0,SEEK_END);
+
+ UnCompressedSize = ftell(UnCompressFile);
+
+ fseek(UnCompressFile,0,SEEK_SET);
+
+ UnCompressedBuffer = malloc (UnCompressedSize);
+
+ if (UnCompressedBuffer == NULL) {
+ printf("Error while allocate memory! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CompressedBuffer = malloc (UnCompressedSize);
+
+ if (CompressedBuffer == NULL) {
+ printf("Error while allocate memory! \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (UnCompressedBuffer, 1, (size_t) UnCompressedSize, UnCompressFile) == (size_t) UnCompressedSize) {
+ CompressedSize = UnCompressedSize;
+
+ Status = EfiCompress ( UnCompressedBuffer,
+ UnCompressedSize,
+ CompressedBuffer,
+ &CompressedSize);
+
+ if (EFI_ERROR(Status)) {
+ printf("Error while do compress operation! \n");
+ return EFI_ABORTED;
+ }
+
+ if (CompressedSize > UnCompressedSize) {
+ printf("Error while do compress operation! \n");
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error while reading file %s! \n", InputFileName);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Write the compressed data into output file
+ //
+ if (fwrite (CompressedBuffer, 1, (size_t) CompressedSize, CompressedFile) != (size_t) CompressedSize) {
+ Error ("FMMT", 0, 0004, "error writing %s file", OutPutFileName);
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ */
+
+ //
+ // Call GenSec tool to generate the compressed section.
+ //
+ LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_STD");
+
+ } else if (CompressionType == EFI_NOT_COMPRESSED) {
+
+ LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_NONE");
+
+ } else {
+ printf ("Error while generate compressed section, unknown compression type! \n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ IN ENCAP_INFO_DATA *CurrentEncapData,
+ IN UINT32 Level_Break,
+ OUT FFS_INFORMATION **OutputFile
+)
+{
+ EFI_STATUS Status;
+ UINT32 ParentType;
+ UINT8 ParentLevel;
+ UINT32 Type;
+ UINT8 Level;
+ CHAR8 *InfFileName;
+ FILE *InfFile;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ ENCAP_INFO_DATA *LocalEncapDataNext;
+ BOOLEAN FfsFoundFlag;
+ UINT32 Index;
+ UINT32 OuterIndex;
+ CHAR8 *ExtractionTool;
+ BOOLEAN IsLastLevelFfs;
+ BOOLEAN IsLeafFlagIgnore;
+ BOOLEAN FirstInFlag;
+ BOOLEAN OutputFileNameListFlag;
+ CHAR8 *InputFileName;
+ CHAR8 *OutputFileName;
+ FFS_INFORMATION *OutputFileNameList;
+ FFS_INFORMATION *ChildFileNameList;
+ FFS_INFORMATION *NewFileNameList;
+ CHAR8 *FvGuidName;
+ UINT16 GuidAttributes;
+ UINT16 GuidDataOffset;
+ BOOLEAN IsRootFv;
+ BOOLEAN IsLargeFile;
+ UINT32 EncapFvStart;
+ UINT32 EncapFvIndex;
+ CHAR8 *TmpFileName;
+ FILE *TmpFile;
+ FILE *InputFile;
+ FILE *OutFile;
+ UINT32 InputFileSize;
+ UINT32 OutputFileSize;
+ UINT32 LargeFileSize;
+ UINT8 *Buffer = NULL;
+ UINT8 SectionHeader[4] = { 0x00, 0x00, 0x00, 0x00 };
+ UINT32 Id;
+ UINT32 SubFvId;
+ UINT32 header;
+ UINT8 AlignN;
+ UINT8 AlignV[1] = {0xFF};
+ AlignN = 0;
+ Id = 0;
+ InputFileSize = 0;
+ EncapFvIndex = 0;
+ Index = 0;
+ OuterIndex = 0;
+ ParentType = 0;
+ ParentLevel = 0;
+ Type = 0;
+ Level = 0;
+ SubFvId = 0;
+ FfsFoundFlag = FALSE;
+ LocalEncapDataTemp = NULL;
+ LocalEncapDataNext = NULL;
+ ExtractionTool = NULL;
+ InputFileName = NULL;
+ OutputFileName = NULL;
+ IsLastLevelFfs = TRUE;
+ IsLeafFlagIgnore = FALSE;
+ FirstInFlag = TRUE;
+ FvGuidName = NULL;
+ OutputFileNameListFlag = TRUE;
+ IsLargeFile = FALSE;
+ OutputFileSize = 0;
+ LargeFileSize = 0x1000000;
+
+
+ OutputFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION));
+ if (OutputFileNameList == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ OutputFileNameList->FFSName = NULL;
+ OutputFileNameList->InFvId = 0;
+ OutputFileNameList->IsFFS = FALSE;
+ OutputFileNameList->ParentLevel = 0;
+ OutputFileNameList->Next = NULL;
+ OutputFileNameList->UiNameSize = 0;
+ OutputFileNameList->Depex = NULL;
+ OutputFileNameList->DepexLen = 0;
+ OutputFileNameList->FfsFoundFlag = FALSE;
+
+ ChildFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION));
+ if (ChildFileNameList == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ChildFileNameList->FFSName = NULL;
+ ChildFileNameList->InFvId = 0;
+ ChildFileNameList->ParentLevel = 0;
+ ChildFileNameList->Next = NULL;
+ ChildFileNameList->IsFFS = FALSE;
+ ChildFileNameList->UiNameSize = 0;
+ ChildFileNameList->Depex = NULL;
+ ChildFileNameList->DepexLen = 0;
+ ChildFileNameList->FfsFoundFlag = FALSE;
+ //
+ // Encapsulate from the lowest FFS file level.
+ //
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+
+ if (CurrentEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+ LocalEncapDataTemp = LocalEncapData->RightNode;
+ while (LocalEncapDataTemp != NULL) {
+ LocalEncapDataNext = LocalEncapDataTemp->NextNode;
+ if (LocalEncapDataNext != NULL && LocalEncapDataNext->NextNode != NULL) {
+
+ LibEncapNewFvFile(FvInFd, TemDir, LocalEncapDataTemp, 1, &ChildFileNameList);
+ ChildFileNameList->ParentLevel = LocalEncapDataTemp->Level -1;
+ if (FvInFd->ChildFvFFS == NULL) {
+ FvInFd->ChildFvFFS = ChildFileNameList;
+ } else {
+ NewFileNameList = FvInFd->ChildFvFFS;
+ while (NewFileNameList->Next != NULL) {
+ NewFileNameList = NewFileNameList->Next;
+ }
+ NewFileNameList->Next = ChildFileNameList;
+ }
+ }
+ LocalEncapDataTemp = LocalEncapDataTemp->RightNode;
+ }
+ }
+
+ if (LocalEncapData->Level > Level) {
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+ ParentLevel = Level;
+ ParentType = Type;
+ }
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ } else {
+ LocalEncapData = CurrentEncapData;
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->Level > Level) {
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) {
+ ParentLevel = Level;
+ ParentType = Type;
+ }
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+
+ do {
+ switch (ParentType) {
+ case FMMT_ENCAP_TREE_FV:
+ OutputFileNameListFlag = TRUE;
+ EncapFvStart = 0;
+ for(OuterIndex=0;OutputFileNameListFlag;OuterIndex++){
+ //
+ // Generate FV.inf attributes.
+ //
+ InfFileName = LibFilenameStrExtended (strrchr(GenTempFile (),OS_SEP), TemDir, "inf");
+ FirstInFlag = TRUE;
+
+ InfFile = fopen (InfFileName, "wt+");
+
+ if (InfFile == NULL) {
+ Error ("FMMT", 0, 0004, "Could not open inf file %s to store FV information! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+
+ if (CurrentEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ } else {
+ LocalEncapData = CurrentEncapData;
+ }
+
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ //
+ // FV GUID Name memory allocation
+ //
+ FvGuidName = (CHAR8 *) malloc (255);
+
+ if (FvGuidName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+
+ memset(FvGuidName, '\0', 255);
+
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+ LocalEncapData->FvExtHeader->FvName.Data1,
+ LocalEncapData->FvExtHeader->FvName.Data2,
+ LocalEncapData->FvExtHeader->FvName.Data3,
+ LocalEncapData->FvExtHeader->FvName.Data4[0],
+ LocalEncapData->FvExtHeader->FvName.Data4[1],
+ LocalEncapData->FvExtHeader->FvName.Data4[2],
+ LocalEncapData->FvExtHeader->FvName.Data4[3],
+ LocalEncapData->FvExtHeader->FvName.Data4[4],
+ LocalEncapData->FvExtHeader->FvName.Data4[5],
+ LocalEncapData->FvExtHeader->FvName.Data4[6],
+ LocalEncapData->FvExtHeader->FvName.Data4[7]
+ );
+
+ } else {
+ FvGuidName = NULL;
+ }
+
+
+ if (ParentLevel == 1) {
+ Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, TRUE);
+ } else {
+ Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, FALSE);
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "generate FV INF file [Options] section failed.");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ Status = LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->Attributes, InfFile);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV header attribute failed");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (LocalEncapData->FvExtHeader != NULL) {
+ Status = LibGenExtFile(LocalEncapData->FvExtHeader, InfFile);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV EXT header failed");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ FvGuidName = NULL;
+ }
+
+ if (CurrentEncapData != NULL) {
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+ if ((memcmp(&FvInFd->FfsAttuibutes[Index].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) {
+ SubFvId = Index;
+ break;
+ }
+ }
+ }
+ //
+ // Found FFSs from Fv structure.
+ //
+ FfsFoundFlag = FALSE;
+ IsRootFv = FALSE;
+ for (Index=0; Index <= FvInFd->FfsNumbers; Index++) {
+ if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == FALSE){
+ break;
+ }
+ if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE){
+ if (Index == EncapFvIndex) {
+ if (FirstInFlag) {
+ Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, TRUE);
+ FirstInFlag = FALSE;
+ } else {
+ Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, FALSE);
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ }
+ }
+
+ NewFileNameList = FvInFd->ChildFvFFS;
+ while (NewFileNameList != NULL && NewFileNameList -> FFSName != NULL) {
+ if (NewFileNameList -> ParentLevel == ParentLevel && Index == NewFileNameList->InFvId && NewFileNameList->FfsFoundFlag==TRUE) {
+ if (FirstInFlag) {
+ Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, TRUE);
+ FirstInFlag = FALSE;
+ } else {
+ Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, FALSE);
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ }
+ NewFileNameList = NewFileNameList->Next;
+ }
+
+ if (FvInFd->FfsAttuibutes[Index].IsHandle==TRUE) {
+ continue;
+ }
+ if (SubFvId > 0 && Index < SubFvId) {
+ continue;
+ }
+
+ //
+ // For the last level FFS, the level below FFSs we should not care the IsLeaf Flag.
+ //
+ if (IsLastLevelFfs) {
+ IsLeafFlagIgnore = TRUE;
+ } else {
+ IsLeafFlagIgnore = FvInFd->FfsAttuibutes[Index].IsLeaf;
+ }
+
+ if (FvInFd->FfsAttuibutes[Index].Level >= ParentLevel + 1 && IsLeafFlagIgnore) {
+ if (FirstInFlag) {
+ if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) {
+ FfsFoundFlag = TRUE;
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, TRUE);
+ FirstInFlag = FALSE;
+ FvInFd->FfsAttuibutes[Index].IsHandle=TRUE;
+ EncapFvStart = Index;
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (Index == 0) {
+ // Root FV need to include all FFS files.
+ IsRootFv = TRUE;
+ }
+ } else {
+ if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) {
+ FfsFoundFlag = TRUE;
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+ FvInFd->FfsAttuibutes[Index].IsHandle=TRUE;
+ }
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ fclose (InfFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (Index == 0) {
+ // Root FV need to include all FFS files.
+ IsRootFv = TRUE;
+ }
+ }
+
+
+ //avoid a FV contain too many ffs files
+ if ((!IsRootFv) && (FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) && (FvInFd->FfsAttuibutes[Index+1].FvLevel <= FvInFd->MulFvLevel) &&
+ (FvInFd->FfsAttuibutes[Index].FvLevel != FvInFd->FfsAttuibutes[Index+1].FvLevel) && (ParentLevel != 1) && (FvInFd->FfsAttuibutes[Index].Level != FvInFd->FfsAttuibutes[Index+1].Level) &&
+ FvInFd->FfsAttuibutes[Index].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0x0){
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ break;
+ }else{
+ if (FvInFd->FfsAttuibutes[Index].Level != 0xFF){
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ }
+ }
+
+ }
+ }
+ // The Fv may has multiple level (> 2), when it is in the FvLevel == 2, we set the IsLastLevelFfs Flag
+ if (Index <=FvInFd->FfsNumbers && FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) {
+ if (FvInFd->FfsAttuibutes[Index].FvLevel == 2) {
+ IsLastLevelFfs = FALSE;
+ }
+ }
+ if (!FfsFoundFlag){
+ OutputFileNameListFlag = FALSE;
+ if (OuterIndex > 0){
+ fclose (InfFile);
+ break;
+ }
+ }
+ //
+ // Create FV
+ //
+ fclose (InfFile);
+
+ EncapFvIndex = EncapFvStart;
+
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "FV");
+
+ Status = LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileName, FvGuidName, IsLargeFile);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+ if (CurrentEncapData != NULL) {
+ OutputFileNameList->InFvId = EncapFvIndex;
+ if (EncapFvIndex > 0) {
+ memcpy(OutputFileNameList->UiName,FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiName, FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize);
+ OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize;
+ OutputFileNameList->Depex = FvInFd->FfsAttuibutes[EncapFvIndex - 1].Depex;
+ OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[EncapFvIndex - 1].DepexLen;
+ OutputFileNameList->FfsFoundFlag = FfsFoundFlag;
+ }
+ }
+ }
+ break;
+ case FMMT_ENCAP_TREE_FFS:
+
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ InputFileName = OutputFileNameList->FFSName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "ffs");
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ for(;LocalEncapData->NextNode != NULL;) {
+ if(LocalEncapData->FvExtHeader != NULL) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (LocalEncapData->FvExtHeader == NULL) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+
+ if (OutputFileNameList->UiNameSize > 0) {
+ TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp");
+ TmpFile = fopen(TmpFileName, "wb+");
+ if (TmpFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open tmp file %s to store UI section information! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ header = (OutputFileNameList->UiNameSize+4) | (EFI_SECTION_USER_INTERFACE << 24);
+ Index = 0;
+ while (header) {
+ SectionHeader[Index] = header % 0x100;
+ header /= 0x100;
+ Index ++;
+ }
+ InputFile = fopen(InputFileName, "rb+");
+ if (InputFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open input file %s! \n", "");
+ fclose(TmpFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(InputFile, 0, SEEK_SET);
+ fseek(InputFile, 0, SEEK_END);
+ InputFileSize = ftell(InputFile);
+ fseek(InputFile, 0, SEEK_SET);
+
+ Buffer = malloc(InputFileSize+OutputFileNameList->UiNameSize+4);
+ memcpy(Buffer, (CHAR16 *)SectionHeader, 4);
+ memcpy(Buffer + 4, (CHAR16 *)(OutputFileNameList->UiName), OutputFileNameList->UiNameSize);
+ if (fread(Buffer+4+OutputFileNameList->UiNameSize, 1, InputFileSize, InputFile) != InputFileSize) {
+ Error("FMMT", 0, 0004, "Could not open sec file %s to add UI section information! \n", "");
+ fclose(TmpFile);
+ fclose(InputFile);
+ free(Buffer);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fwrite(Buffer, 1, InputFileSize + OutputFileNameList->UiNameSize + 4, TmpFile);
+ free(Buffer);
+ fclose(TmpFile);
+ fclose(InputFile);
+ InputFileName = TmpFileName;
+ }
+ if (OutputFileNameList->DepexLen > 0) {
+ TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp");
+ TmpFile = fopen(TmpFileName, "wb+");
+ if (TmpFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open tmp file %s to store Depex section information! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ InputFile = fopen(InputFileName, "rb+");
+ if (InputFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open input file %s! \n", "");
+ fclose(TmpFile);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(InputFile, 0, SEEK_SET);
+ fseek(InputFile, 0, SEEK_END);
+ InputFileSize = ftell(InputFile);
+ fseek(InputFile, 0, SEEK_SET);
+ // make sure the section is 4 byte align
+ if (OutputFileNameList->DepexLen % 4 != 0) {
+ AlignN = 4 - OutputFileNameList->DepexLen % 4;
+ }
+ Buffer = malloc(InputFileSize + OutputFileNameList->DepexLen + AlignN);
+ memcpy(Buffer, OutputFileNameList->Depex, OutputFileNameList->DepexLen);
+ if (AlignN != 0) {
+ for (Index = 0; Index < AlignN; Index ++) {
+ memcpy(Buffer + OutputFileNameList->DepexLen + Index, AlignV, 1);
+ }
+ }
+ if (fread(Buffer + OutputFileNameList->DepexLen + AlignN, 1, InputFileSize, InputFile) != InputFileSize) {
+ Error("FMMT", 0, 0004, "Could not open sec file %s to add Depex section information! \n", "");
+ fclose(TmpFile);
+ fclose(InputFile);
+ free(Buffer);
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fwrite(Buffer, 1, InputFileSize + OutputFileNameList->DepexLen + AlignN, TmpFile);
+ free(Buffer);
+ fclose(TmpFile);
+ fclose(InputFile);
+ InputFileName = TmpFileName;
+ }
+ for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) {
+ if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(LocalEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){
+ if (access(FvInFd->FfsAttuibutes[Id].FfsName, 0) != -1) {
+ Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[Id].FfsName);
+ if (EFI_ERROR(Status)) {
+ Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ memset(FvInFd->FfsAttuibutes[Id].FfsName, '\0', _MAX_PATH);
+ FvInFd->FfsAttuibutes[Id].Level = 0xFF;
+ break;
+ }
+ }
+ }
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapDataTemp = LocalEncapData->NextNode;
+ if ((LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_GUIDED_SECTION) || (LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_COMPRESS_SECTION)) {
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, "1");
+ }
+ else{
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr);
+ }
+ }
+ else{
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr);
+ }
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ free(LocalEncapData->FvExtHeader);
+ LocalEncapData->FvExtHeader = NULL;
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+ OutputFileNameList->IsFFS = TRUE;
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ case FMMT_ENCAP_TREE_GUIDED_SECTION:
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ //
+ // Create the guided section original data, do compress operation.
+ //
+ InputFileName = OutputFileNameList->FFSName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "compressed");
+
+ //
+ // Use the guided section header guid to find out compress application name.
+ //
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ (EFI_GUID *)LocalEncapData->Data
+ );
+ GuidDataOffset = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID));
+ GuidAttributes = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID) + sizeof (UINT16));
+
+ Status = LibCreateGuidedSectionOriginalData (InputFileName, ExtractionTool, OutputFileName);
+
+ if (EFI_ERROR (Status) || GuidDataOffset < sizeof (EFI_GUID_DEFINED_SECTION)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Compress guided data failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ GuidDataOffset = GuidDataOffset - sizeof (EFI_GUID_DEFINED_SECTION);
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "guided");
+
+ Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_GUID_DEFINED, OutputFileName, NULL, NULL, LibFmmtGuidToStr((EFI_GUID *)LocalEncapData->Data), GuidDataOffset, GuidAttributes, NULL);
+ OutFile = fopen(OutputFileName, "rb+");
+ if (OutFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open the file %s! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(OutFile, 0, SEEK_SET);
+ fseek(OutFile, 0, SEEK_END);
+ OutputFileSize = ftell(OutFile);
+ fclose(OutFile);
+ if (OutputFileSize > LargeFileSize) {
+ IsLargeFile = TRUE;
+ }
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate guided section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ case FMMT_ENCAP_TREE_COMPRESS_SECTION:
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ InputFileName = OutputFileNameList->FFSName;
+
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "comsec");
+ LocalEncapData = CurrentEncapData;
+ if (LocalEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ }
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ Status = LibGenCompressedSection (InputFileName, OutputFileName, *(UINT8 *)(LocalEncapData->Data));
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate compressed section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ case FMMT_ENCAP_TREE_FV_SECTION:
+ while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){
+ InputFileName = OutputFileNameList->FFSName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, 0, 0, NULL);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ //
+ // Make it alignment.
+ //
+ Status = LibCreateFfsSection(FvInFd, InputFileName, NULL, 0, OutputFileName, NULL, NULL, NULL, 0, 0, NULL);
+ OutFile = fopen(OutputFileName, "rb+");
+ if (OutFile == NULL) {
+ Error("FMMT", 0, 0004, "Could not open the file %s! \n", "");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return EFI_ABORTED;
+ }
+ fseek(OutFile, 0, SEEK_SET);
+ fseek(OutFile, 0, SEEK_END);
+ OutputFileSize = ftell(OutFile);
+ fclose(OutFile);
+ if (OutputFileSize > LargeFileSize) {
+ IsLargeFile = TRUE;
+ }
+
+ OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1);
+ if (OutputFileNameList->FFSName == NULL) {
+ Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", "");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1);
+
+ if (EFI_ERROR (Status)) {
+ Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!");
+ free (OutputFileNameList);
+ free (ChildFileNameList);
+ return Status;
+ }
+ if (OutputFileNameList->Next == NULL){
+ break;
+ }
+ OutputFileNameList = OutputFileNameList->Next;
+ }
+ break;
+ default:
+ for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) {
+ if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){
+ FvInFd->FfsAttuibutes[Id].IsHandle = TRUE;
+ memcpy(OutputFileNameList->UiName, FvInFd->FfsAttuibutes[Id].UiName, FvInFd->FfsAttuibutes[Id].UiNameSize);
+ OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[Id].UiNameSize;
+ OutputFileNameList->FFSName = FvInFd->FfsAttuibutes[Id].FfsName;
+ OutputFileNameList->Depex = FvInFd->FfsAttuibutes[Id].Depex;
+ OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[Id].DepexLen;
+ OutputFileNameList->FfsFoundFlag = TRUE;
+ OutputFileNameList->IsFFS = TRUE;
+ OutputFileNameList->InFvId = Id;
+ *OutputFile = OutputFileNameList;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (CurrentEncapData == NULL) {
+ LocalEncapData = FvInFd->EncapData;
+ } else {
+ if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE) {
+ *OutputFile = OutputFileNameList;
+ return EFI_SUCCESS;
+ }
+ LocalEncapData = CurrentEncapData;
+ }
+ ParentLevel -= 1;
+
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ LocalEncapDataTemp = LocalEncapData->NextNode;
+ if ((LocalEncapDataTemp != NULL) && (LocalEncapDataTemp->Level == ParentLevel)) {
+ ParentType = LocalEncapDataTemp->Type;
+ break;
+ }
+ ParentType = LocalEncapData->Type;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ } while (ParentLevel != Level_Break);
+
+ *OutputFile = OutputFileNameList;
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+LibFindFvInEncapData (
+ ENCAP_INFO_DATA *EncapData,
+ UINT8 *Index
+)
+{
+ ENCAP_INFO_DATA *LocalEncapData;
+ LocalEncapData = EncapData;
+ if (LocalEncapData == NULL) {
+ Error("FMMT", 0, 0005, "error while find FV in Encapulate buffer", "Invalid parameters.");
+ return EFI_INVALID_PARAMETER;
+ }
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->RightNode != NULL) {
+ LibFindFvInEncapData (LocalEncapData->RightNode, Index);
+ }
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) {
+ (*Index)++;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibLocateFvViaFvId (
+ IN FIRMWARE_DEVICE *FdData,
+ IN CHAR8 *FvId,
+ IN OUT FV_INFORMATION **FvInFd
+)
+{
+ UINT8 FvIndex1;
+ UINT8 FvIndex2;
+ BOOLEAN FvFoundFlag;
+ CHAR8* FvGuidName;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataRight;
+ ENCAP_INFO_DATA *LocalEncapDataNext;
+ FvIndex1 = 0;
+ FvIndex2 = 0;
+ FvFoundFlag = FALSE;
+ FvGuidName = NULL;
+ LocalEncapDataNext = NULL;
+ LocalEncapDataRight = NULL;
+
+ if (FdData == NULL || FvId == NULL || FvInFd == NULL || FdData->Fv == NULL) {
+ Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid parameters.");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FvInFd = FdData->Fv;
+
+ if (strlen(FvId) < 3) {
+ Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!");
+ return EFI_ABORTED;
+ }
+
+ FvGuidName = (CHAR8 *) malloc (255);
+ if (FvGuidName == NULL) {
+ Error ("FMMT", 0, 0005, "Resource: Memory can't be allocated", NULL);
+ return EFI_ABORTED;
+ }
+ memset(FvGuidName, '\0', 255);
+ LocalEncapData = NULL;
+
+ if (strlen(FvId) == 36) {
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvExtHeader) != NULL) {
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ (*FvInFd)->FvExtHeader->FvName.Data1,
+ (*FvInFd)->FvExtHeader->FvName.Data2,
+ (*FvInFd)->FvExtHeader->FvName.Data3,
+ (*FvInFd)->FvExtHeader->FvName.Data4[0],
+ (*FvInFd)->FvExtHeader->FvName.Data4[1],
+ (*FvInFd)->FvExtHeader->FvName.Data4[2],
+ (*FvInFd)->FvExtHeader->FvName.Data4[3],
+ (*FvInFd)->FvExtHeader->FvName.Data4[4],
+ (*FvInFd)->FvExtHeader->FvName.Data4[5],
+ (*FvInFd)->FvExtHeader->FvName.Data4[6],
+ (*FvInFd)->FvExtHeader->FvName.Data4[7]);
+ if (strcmp(FvGuidName, FvId) == 0) {
+ FvId = (*FvInFd)->FvName;
+ break;
+ }
+ }
+ if ((*FvInFd)->MulFvLevel > 1) {
+ LocalEncapData = (*FvInFd) -> EncapData;
+ LocalEncapData = LocalEncapData->NextNode;
+ while (LocalEncapData != NULL) {
+ if (LocalEncapData->RightNode != NULL) {
+ LocalEncapDataRight = LocalEncapData->RightNode;
+ while (LocalEncapDataRight !=NULL) {
+ if (LocalEncapDataRight->NextNode != NULL) {
+ LocalEncapDataNext = LocalEncapDataRight->NextNode;
+ while (LocalEncapDataNext != NULL) {
+ if (LocalEncapDataNext->Type == FMMT_ENCAP_TREE_FV) {
+ if (LocalEncapDataNext->FvExtHeader != NULL) {
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ LocalEncapDataNext->FvExtHeader->FvName.Data1,
+ LocalEncapDataNext->FvExtHeader->FvName.Data2,
+ LocalEncapDataNext->FvExtHeader->FvName.Data3,
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[0],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[1],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[2],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[3],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[4],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[5],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[6],
+ LocalEncapDataNext->FvExtHeader->FvName.Data4[7]);
+ if (strcmp(FvGuidName, FvId) == 0)
+ {
+ sprintf(FvId, "%s%d", "FV", LocalEncapDataNext->FvId - 1);
+ break;
+ }
+
+ }
+ }
+ LocalEncapDataNext = LocalEncapDataNext->NextNode;
+ }
+ }
+ LocalEncapDataRight = LocalEncapDataRight->RightNode;
+ }
+ }
+ if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) {
+ if (LocalEncapData->FvExtHeader != NULL) {
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ LocalEncapData->FvExtHeader->FvName.Data1,
+ LocalEncapData->FvExtHeader->FvName.Data2,
+ LocalEncapData->FvExtHeader->FvName.Data3,
+ LocalEncapData->FvExtHeader->FvName.Data4[0],
+ LocalEncapData->FvExtHeader->FvName.Data4[1],
+ LocalEncapData->FvExtHeader->FvName.Data4[2],
+ LocalEncapData->FvExtHeader->FvName.Data4[3],
+ LocalEncapData->FvExtHeader->FvName.Data4[4],
+ LocalEncapData->FvExtHeader->FvName.Data4[5],
+ LocalEncapData->FvExtHeader->FvName.Data4[6],
+ LocalEncapData->FvExtHeader->FvName.Data4[7]);
+
+ if (strcmp(FvGuidName, FvId) == 0) {
+ sprintf(FvId, "%s%d", "FV", LocalEncapData->FvId - 1);
+ break;
+ }
+ }
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ }
+ *FvInFd = FdData->Fv;
+ FvIndex1 = (UINT8) atoi (FvId + 2);
+
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvName) != NULL) {
+ FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+ LocalEncapData = (*FvInFd)->EncapData;
+ LibFindFvInEncapData (LocalEncapData, &FvIndex2);
+
+ if ((FvIndex2 - 1 >= FvIndex1)) {
+ FvFoundFlag = TRUE;
+ break;
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ //
+ // The specified FV id has issue, can not find the FV in FD.
+ //
+ if (!FvFoundFlag) {
+ Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!");
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+)
+{
+ EFI_GUID Guid;
+ STRING_LIST *Tool;
+ GUID_SEC_TOOL_ENTRY *FirstGuidTool;
+ GUID_SEC_TOOL_ENTRY *LastGuidTool;
+ GUID_SEC_TOOL_ENTRY *NewGuidTool;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
+ "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
+ "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
+ "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
+ "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
+ };
+
+ Tool = NULL;
+ FirstGuidTool = NULL;
+ LastGuidTool = NULL;
+ NewGuidTool = NULL;
+ Index = 0;
+
+ for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
+ Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
+ if ((Tool != NULL) &&
+ (Tool->Count == 3)
+ ) {
+ Status = StringToGuid (Tool->Strings[0], &Guid);
+ if (!EFI_ERROR (Status)) {
+ NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
+ if (NewGuidTool != NULL) {
+ memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
+ NewGuidTool->Name = CloneString(Tool->Strings[1]);
+ NewGuidTool->Path = CloneString(Tool->Strings[2]);
+ NewGuidTool->Next = NULL;
+ } else {
+ printf ("Error while allocate resource! \n");
+ FreeStringList (Tool);
+ return NULL;
+ }
+ if (FirstGuidTool == NULL) {
+ FirstGuidTool = NewGuidTool;
+ } else {
+ LastGuidTool->Next = NewGuidTool;
+ }
+ LastGuidTool = NewGuidTool;
+ }
+ } else {
+ fprintf (stdout, "Error");
+ }
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ Tool = NULL;
+ }
+ }
+ return FirstGuidTool;
+}
diff --git a/Platform/Intel/Tools/FMMT/GNUmakefile b/Platform/Intel/Tools/FMMT/GNUmakefile
new file mode 100644
index 0000000000..911d747451
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/GNUmakefile
@@ -0,0 +1,16 @@
+## @file
+# GNU/Linux makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = FMMT
+
+LIBS = -lCommon
+
+OBJECTS = FmmtLib.o Rebase.o FirmwareModuleManagement.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
diff --git a/Platform/Intel/Tools/FMMT/Makefile b/Platform/Intel/Tools/FMMT/Makefile
new file mode 100644
index 0000000000..1a96e0e27f
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/Makefile
@@ -0,0 +1,17 @@
+## @file
+# Windows makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = FMMT
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = FirmwareModuleManagement.obj FmmtLib.obj Rebase.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
diff --git a/Platform/Intel/Tools/FMMT/Rebase.c b/Platform/Intel/Tools/FMMT/Rebase.c
new file mode 100644
index 0000000000..d32217d18c
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/Rebase.c
@@ -0,0 +1,846 @@
+/** @file
+
+ Library to rebase PE image.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Rebase.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <PeCoffLib.h>
+#include <CommonLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <FvLib.h>
+#include "EfiUtilityMsgs.h"
+
+static
+EFI_STATUS
+FfsRebaseImageRead(
+IN VOID *FileHandle,
+IN UINTN FileOffset,
+IN OUT UINT32 *ReadSize,
+OUT VOID *Buffer
+);
+
+EFI_STATUS
+RebaseFfs(
+IN OUT UINT64 BaseAddress,
+IN CHAR8 *FileName,
+IN OUT EFI_FFS_FILE_HEADER *FfsFile,
+IN UINTN XipOffset
+)
+/*++
+
+Routine Description:
+
+This function determines if a file is XIP and should be rebased. It will
+rebase any PE32 sections found in the file using the base address.
+
+Arguments:
+
+FvInfo A pointer to FV_INFO struture.
+FileName Ffs File PathName
+FfsFile A pointer to Ffs file image.
+XipOffset The offset address to use for rebasing the XIP file image.
+
+Returns:
+
+EFI_SUCCESS The image was properly rebased.
+EFI_INVALID_PARAMETER An input parameter is invalid.
+EFI_ABORTED An error occurred while rebasing the input file image.
+EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+EFI_NOT_FOUND No compressed sections could be found.
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext;
+ EFI_PHYSICAL_ADDRESS XipBase;
+ EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;
+ UINTN Index;
+ EFI_FILE_SECTION_POINTER CurrentPe32Section;
+ EFI_FFS_FILE_STATE SavedState;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_TE_IMAGE_HEADER *TEImageHeader;
+ UINT8 *MemoryImagePointer;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+ CHAR8 PeFileName[MAX_LONG_FILE_PATH];
+ CHAR8 *Cptr;
+ FILE *PeFile;
+ UINT8 *PeFileBuffer;
+ UINT32 PeFileSize;
+ CHAR8 *PdbPointer;
+ UINT32 FfsHeaderSize;
+ UINT32 CurSecHdrSize;
+ CHAR8 *LongFilePathName;
+
+ Index = 0;
+ MemoryImagePointer = NULL;
+ TEImageHeader = NULL;
+ ImgHdr = NULL;
+ SectionHeader = NULL;
+ Cptr = NULL;
+ PeFile = NULL;
+ PeFileBuffer = NULL;
+
+ //
+ // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
+ //
+ if (BaseAddress == 0) {
+ return EFI_SUCCESS;
+ }
+
+ XipBase = BaseAddress + XipOffset;
+
+ //
+ // We only process files potentially containing PE32 sections.
+ //
+ switch (FfsFile->Type) {
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+ case EFI_FV_FILETYPE_DRIVER:
+ case EFI_FV_FILETYPE_DXE_CORE:
+ break;
+ case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
+ //
+ // Rebase the inside FvImage.
+ //
+ GetChildFvFromFfs (BaseAddress, FfsFile, XipOffset);
+
+ //
+ // Search PE/TE section in FV sectin.
+ //
+ break;
+ default:
+ return EFI_SUCCESS;
+ }
+
+ FfsHeaderSize = GetFfsHeaderLength(FfsFile);
+ //
+ // Rebase each PE32 section
+ //
+ Status = EFI_SUCCESS;
+ for (Index = 1;; Index++) {
+ //
+ // Init Value
+ //
+ NewPe32BaseAddress = 0;
+
+ //
+ // Find Pe Image
+ //
+ Status = GetSectionByType(FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+ //
+ // Initialize context
+ //
+ memset(&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+
+ //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+ // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+ // mArm = TRUE;
+ //}
+
+ //
+ // Keep Image Context for PE image in FV
+ //
+ memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+ //
+ // Get File PdbPointer
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+ if (PdbPointer == NULL) {
+ PdbPointer = FileName;
+ }
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);
+
+ //
+ // Calculate the PE32 base address, based on file type
+ //
+ switch (FfsFile->Type) {
+ case EFI_FV_FILETYPE_SECURITY_CORE:
+ case EFI_FV_FILETYPE_PEI_CORE:
+ case EFI_FV_FILETYPE_PEIM:
+ case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
+ //
+ // Check if section-alignment and file-alignment match or not
+ //
+ if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+ //
+ // Xip module has the same section alignment and file alignment.
+ //
+ Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+ return EFI_ABORTED;
+ }
+ //
+ // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
+ //
+ if (ImageContext.RelocationsStripped) {
+ //
+ // Construct the original efi file Name
+ //
+ if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+ Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+ return EFI_ABORTED;
+ }
+ strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+ PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+ Cptr = PeFileName + strlen(PeFileName);
+ while (*Cptr != '.') {
+ Cptr--;
+ }
+ if (*Cptr != '.') {
+ Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ return EFI_ABORTED;
+ }
+ else {
+ *(Cptr + 1) = 'e';
+ *(Cptr + 2) = 'f';
+ *(Cptr + 3) = 'i';
+ *(Cptr + 4) = '\0';
+ }
+ LongFilePathName = LongFilePath(PeFileName);
+ if (LongFilePathName == NULL) {
+ Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+ return EFI_ABORTED;
+ }
+ PeFile = fopen(LongFilePathName, "rb");
+ if (PeFile == NULL) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ //return EFI_ABORTED;
+ break;
+ }
+ //
+ // Get the file size
+ //
+ PeFileSize = _filelength(fileno(PeFile));
+ PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+ if (PeFileBuffer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ fclose(PeFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read Pe File
+ //
+ fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+ //
+ // close file
+ //
+ fclose(PeFile);
+ //
+ // Handle pointer to the original efi image.
+ //
+ ImageContext.Handle = PeFileBuffer;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+ ImageContext.RelocationsStripped = FALSE;
+ }
+
+ NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+ break;
+
+ case EFI_FV_FILETYPE_DRIVER:
+ case EFI_FV_FILETYPE_DXE_CORE:
+ //
+ // Check if section-alignment and file-alignment match or not
+ //
+ if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
+ //
+ // Xip module has the same section alignment and file alignment.
+ //
+ Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
+ return EFI_ABORTED;
+ }
+ NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
+ break;
+
+ default:
+ //
+ // Not supported file type
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Relocation doesn't exist
+ //
+ if (ImageContext.RelocationsStripped) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ continue;
+ }
+
+ //
+ // Relocation exist and rebase
+ //
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy Relocated data to raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(
+ (UINTN)ImgHdr +
+ sizeof (UINT32)+
+ sizeof (EFI_IMAGE_FILE_HEADER)+
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
+ CopyMem(
+ (UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+
+ free((VOID *)MemoryImagePointer);
+ MemoryImagePointer = NULL;
+ if (PeFileBuffer != NULL) {
+ free(PeFileBuffer);
+ PeFileBuffer = NULL;
+ }
+
+ //
+ // Update Image Base Address
+ //
+ if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32)NewPe32BaseAddress;
+ }
+ else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
+ }
+ else {
+ Error(NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
+ ImgHdr->Pe32.OptionalHeader.Magic,
+ FileName
+ );
+ return EFI_ABORTED;
+ }
+
+ //
+ // Now update file checksum
+ //
+ if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ SavedState = FfsFile->State;
+ FfsFile->IntegrityCheck.Checksum.File = 0;
+ FfsFile->State = 0;
+ FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+ (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+ GetFfsFileLength(FfsFile) - FfsHeaderSize
+ );
+ FfsFile->State = SavedState;
+ }
+
+ }
+
+ if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
+ FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
+ FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
+ FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&
+ FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
+ ) {
+ //
+ // Only Peim code may have a TE section
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Now process TE sections
+ //
+ for (Index = 1;; Index++) {
+ NewPe32BaseAddress = 0;
+
+ //
+ // Find Te Image
+ //
+ Status = GetSectionByType(FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+
+ CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
+
+ //
+ // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
+ // by GenTEImage
+ //
+ TEImageHeader = (EFI_TE_IMAGE_HEADER *)((UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize);
+
+ //
+ // Initialize context, load image info.
+ //
+ memset(&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *)TEImageHeader;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+
+ //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
+ // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+ // mArm = TRUE;
+ //}
+
+ //
+ // Keep Image Context for TE image in FV
+ //
+ memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext));
+
+ //
+ // Get File PdbPointer
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle);
+ if (PdbPointer == NULL) {
+ PdbPointer = FileName;
+ }
+ //
+ // Set new rebased address.
+ //
+ NewPe32BaseAddress = XipBase + (UINTN)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
+ - TEImageHeader->StrippedSize - (UINTN)FfsFile;
+
+ //
+ // if reloc is stripped, try to get the original efi image to get reloc info.
+ //
+ if (ImageContext.RelocationsStripped) {
+ //
+ // Construct the original efi file name
+ //
+ if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
+ Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName);
+ return EFI_ABORTED;
+ }
+ strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1);
+ PeFileName[MAX_LONG_FILE_PATH - 1] = 0;
+ Cptr = PeFileName + strlen(PeFileName);
+ while (*Cptr != '.') {
+ Cptr--;
+ }
+
+ if (*Cptr != '.') {
+ Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ return EFI_ABORTED;
+ }
+ else {
+ *(Cptr + 1) = 'e';
+ *(Cptr + 2) = 'f';
+ *(Cptr + 3) = 'i';
+ *(Cptr + 4) = '\0';
+ }
+
+ LongFilePathName = LongFilePath(PeFileName);
+ if (LongFilePathName == NULL) {
+ Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName);
+ return EFI_ABORTED;
+ }
+ PeFile = fopen(LongFilePathName, "rb");
+ if (PeFile == NULL) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
+ //return EFI_ABORTED;
+ }
+ else {
+ //
+ // Get the file size
+ //
+ PeFileSize = _filelength(fileno(PeFile));
+ PeFileBuffer = (UINT8 *)malloc(PeFileSize);
+ if (PeFileBuffer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ fclose(PeFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read Pe File
+ //
+ fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
+ //
+ // close file
+ //
+ fclose(PeFile);
+ //
+ // Append reloc section into TeImage
+ //
+ ImageContext.Handle = PeFileBuffer;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status);
+ return Status;
+ }
+ ImageContext.RelocationsStripped = FALSE;
+ }
+ }
+ //
+ // Relocation doesn't exist
+ //
+ if (ImageContext.RelocationsStripped) {
+ Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
+ continue;
+ }
+
+ //
+ // Relocation exist and rebase
+ //
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+ //
+ // Reloacate TeImage
+ //
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage(&ImageContext);
+ if (EFI_ERROR(Status)) {
+ Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
+ free((VOID *)MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy the relocated image into raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(TEImageHeader + 1);
+ for (Index = 0; Index < TEImageHeader->NumberOfSections; Index++, SectionHeader++) {
+ if (!ImageContext.IsTeImage) {
+ CopyMem(
+ (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+ else {
+ CopyMem(
+ (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
+ (VOID*)(UINTN)(ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+ }
+
+ //
+ // Free the allocated memory resource
+ //
+ free((VOID *)MemoryImagePointer);
+ MemoryImagePointer = NULL;
+ if (PeFileBuffer != NULL) {
+ free(PeFileBuffer);
+ PeFileBuffer = NULL;
+ }
+
+ //
+ // Update Image Base Address
+ //
+ TEImageHeader->ImageBase = NewPe32BaseAddress;
+
+ //
+ // Now update file checksum
+ //
+ if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ SavedState = FfsFile->State;
+ FfsFile->IntegrityCheck.Checksum.File = 0;
+ FfsFile->State = 0;
+ FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8(
+ (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
+ GetFfsFileLength(FfsFile) - FfsHeaderSize
+ );
+ FfsFile->State = SavedState;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FfsRebaseImageRead(
+IN VOID *FileHandle,
+IN UINTN FileOffset,
+IN OUT UINT32 *ReadSize,
+OUT VOID *Buffer
+)
+/*++
+
+Routine Description:
+
+Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+
+FileHandle - The handle to the PE/COFF file
+
+FileOffset - The offset, in bytes, into the file to read
+
+ReadSize - The number of bytes to read from the file starting at FileOffset
+
+Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+
+EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINT32 Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetChildFvFromFfs (
+ IN UINT64 BaseAddress,
+ IN EFI_FFS_FILE_HEADER *FfsFile,
+ IN UINTN XipOffset
+ )
+/*++
+
+Routine Description:
+
+ This function gets all child FvImages in the input FfsFile, and records
+ their base address to the parent image.
+
+Arguments:
+ FvInfo A pointer to FV_INFO struture.
+ FfsFile A pointer to Ffs file image that may contain FvImage.
+ XipOffset The offset address to the parent FvImage base.
+
+Returns:
+
+ EFI_SUCCESS Base address of child Fv image is recorded.
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_FILE_SECTION_POINTER SubFvSection;
+ EFI_FIRMWARE_VOLUME_HEADER *SubFvImageHeader;
+ EFI_PHYSICAL_ADDRESS SubFvBaseAddress;
+ EFI_FIRMWARE_VOLUME_HEADER *OrigFvHeader;
+ UINT32 OrigFvLength;
+ EFI_PHYSICAL_ADDRESS OrigFvBaseAddress;
+ EFI_FFS_FILE_HEADER *CurrentFile;
+
+ //
+ // Initialize FV library, saving previous values
+ //
+ OrigFvHeader = NULL;
+ GetFvHeader (&OrigFvHeader, &OrigFvLength);
+ OrigFvBaseAddress = BaseAddress;
+ for (Index = 1;; Index++) {
+ //
+ // Find FV section
+ //
+ Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));
+
+ //
+ // Rebase on Flash
+ //
+ SubFvBaseAddress = OrigFvBaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;
+ //mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;
+ BaseAddress = SubFvBaseAddress;
+ InitializeFvLib(SubFvImageHeader, (UINT32) SubFvImageHeader->FvLength);
+
+ Status = GetNextFile (NULL, &CurrentFile);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error parsing FV image", "FFS file can't be found");
+ continue;
+ }
+ while (CurrentFile) {
+ RebaseFfs (BaseAddress, "", CurrentFile, (UINTN) CurrentFile - (UINTN) SubFvImageHeader);
+ Status = GetNextFile (CurrentFile, &CurrentFile);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ BaseAddress = OrigFvBaseAddress;
+ if (OrigFvHeader != NULL) {
+ InitializeFvLib(OrigFvHeader, OrigFvLength);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetPe32Info (
+ IN UINT8 *Pe32,
+ OUT UINT32 *EntryPoint,
+ OUT UINT32 *BaseOfCode,
+ OUT UINT16 *MachineType
+ )
+/*++
+
+Routine Description:
+
+ Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
+ See EfiImage.h for machine types. The entry point offset is from the beginning
+ of the PE32 buffer passed in.
+
+Arguments:
+
+ Pe32 Beginning of the PE32.
+ EntryPoint Offset from the beginning of the PE32 to the image entry point.
+ BaseOfCode Base address of code.
+ MachineType Magic number for the machine type.
+
+Returns:
+
+ EFI_SUCCESS Function completed successfully.
+ EFI_ABORTED Error encountered.
+ EFI_INVALID_PARAMETER A required parameter was NULL.
+ EFI_UNSUPPORTED The operation is unsupported.
+
+--*/
+{
+ EFI_IMAGE_DOS_HEADER *DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_TE_IMAGE_HEADER *TeHeader;
+
+ //
+ // Verify input parameters
+ //
+ if (Pe32 == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // First check whether it is one TE Image.
+ //
+ TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
+ if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ //
+ // By TeImage Header to get output
+ //
+ *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+ *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
+ *MachineType = TeHeader->Machine;
+ } else {
+
+ //
+ // Then check whether
+ // First is the DOS header
+ //
+ DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
+
+ //
+ // Verify DOS header is expected
+ //
+ if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Immediately following is the NT header.
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
+
+ //
+ // Verify NT header is expected
+ //
+ if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get output
+ //
+ *EntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
+ *BaseOfCode = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
+ *MachineType = ImgHdr->Pe32.FileHeader.Machine;
+ }
+
+ //
+ // Verify machine type is supported
+ //
+ if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&
+ (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {
+ Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/Tools/FMMT/Rebase.h b/Platform/Intel/Tools/FMMT/Rebase.h
new file mode 100644
index 0000000000..57604a357f
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/Rebase.h
@@ -0,0 +1,31 @@
+/** @file Rebase.h
+
+ Library to rebase PE image.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FMMT_REBASE_H
+#define _FMMT_REBASE_H
+
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareFile.h>
+
+EFI_STATUS
+RebaseFfs(
+IN OUT UINT64 BaseAddress,
+IN CHAR8 *FileName,
+IN OUT EFI_FFS_FILE_HEADER *FfsFile,
+IN UINTN XipOffset
+);
+
+EFI_STATUS
+GetChildFvFromFfs (
+ IN UINT64 BaseAddress,
+ IN EFI_FFS_FILE_HEADER *FfsFile,
+ IN UINTN XipOffset
+);
+
+#endif
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib
2019-06-21 1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
2019-06-21 1:26 ` [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT Zhang, Shenglei
@ 2019-06-21 1:26 ` Zhang, Shenglei
2019-06-21 1:26 ` [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE Zhang, Shenglei
` (4 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21 1:26 UTC (permalink / raw)
To: devel; +Cc: Bob Feng, Liming Gao
BmfLib is added for FCE tool.
https://bugzilla.tianocore.org/show_bug.cgi?id=1848
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
Platform/Intel/Tools/BfmLib/BfmLib.c | 4355 ++++++++++++++++++
Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 ++++
Platform/Intel/Tools/BfmLib/BinFileManager.h | 439 ++
Platform/Intel/Tools/BfmLib/GNUmakefile | 15 +
Platform/Intel/Tools/BfmLib/Makefile | 17 +
5 files changed, 5850 insertions(+)
create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
diff --git a/Platform/Intel/Tools/BfmLib/BfmLib.c b/Platform/Intel/Tools/BfmLib/BfmLib.c
new file mode 100644
index 0000000000..9dedda3da2
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/BfmLib.c
@@ -0,0 +1,4355 @@
+/** @file
+
+ Library to process EFI image.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinFileManager.h"
+
+#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
+ ( \
+ (BOOLEAN) ( \
+ (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
+ ) \
+ )
+
+#ifndef __GNUC__
+#define DECODE_STR "%s -d -o \"%s\" \"%s\" > NUL"
+#define ENCODE_STR "%s -e \"%s\" -o \"%s\" > NUL"
+#define GENSEC_COMPRESSION "GenSec -s %s -c %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_GUID "GenSec -s %s -r PROCESSING_REQUIRED -g %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_STR "GenSec -s %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_ALIGN "GenSec --sectionalign 16 \"%s\" -o \"%s\" > NUL"
+#define GENFV_STR "GenFv -i \"%s\" -o \"%s\" > NUL"
+#define GENFV_FVGUID "GenFv -i \"%s\" -o \"%s\" --FvNameGuid %s > NUL"
+#define GENFV_FFS "GenFv -f \"%s\" -g %s -o \"%s\" > NUL"
+#define GENFFS_STR "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" > NUL"
+#define GENFFS_FIX "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" > NUL"
+#else
+#define DECODE_STR "%s -d -o \"%s\" \"%s\" > /dev/null"
+#define ENCODE_STR "%s -e \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_COMPRESSION "GenSec -s %s -c %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_GUID "GenSec -s %s -r PROCESSING_REQUIRED -g %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_STR "GenSec -s %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_ALIGN "GenSec --sectionalign 16 \"%s\" -o \"%s\" > /dev/null"
+#define GENFV_STR "GenFv -i \"%s\" -o \"%s\" > /dev/null"
+#define GENFV_FVGUID "GenFv -i \"%s\" -o \"%s\" --FvNameGuid %s > /dev/null"
+#define GENFV_FFS "GenFv -f \"%s\" -g %s -o \"%s\" > /dev/null"
+#define GENFFS_STR "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" > /dev/null"
+#define GENFFS_FIX "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" > /dev/null"
+#endif
+
+#define DECODE_STR_ERR "%s -d -o \"%s\" \"%s\" "
+#define ENCODE_STR_ERR "%s -e \"%s\" -o \"%s\" "
+
+CHAR8 mFirmwareFileSystem2Guid[16] = {0x78, 0xE5, 0x8C, 0x8C, 0x3D, 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3};
+
+CHAR8 mFirmwareFileSystem3Guid[16] = {0x7A, 0xC0, 0x73, 0x54, 0xCB, 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A };
+extern CHAR8* mGuidToolDefinition;
+UINT32 PadSizeOfBfv;
+
+static CHAR8 *mSectionTypeName[] = {
+ NULL, // 0x00 - reserved
+ "EFI_SECTION_COMPRESSION", // 0x01
+ "EFI_SECTION_GUID_DEFINED", // 0x02
+ NULL, // 0x03 - reserved
+ NULL, // 0x04 - reserved
+ NULL, // 0x05 - reserved
+ NULL, // 0x06 - reserved
+ NULL, // 0x07 - reserved
+ NULL, // 0x08 - reserved
+ NULL, // 0x09 - reserved
+ NULL, // 0x0A - reserved
+ NULL, // 0x0B - reserved
+ NULL, // 0x0C - reserved
+ NULL, // 0x0D - reserved
+ NULL, // 0x0E - reserved
+ NULL, // 0x0F - reserved
+ "EFI_SECTION_PE32", // 0x10
+ "EFI_SECTION_PIC", // 0x11
+ "EFI_SECTION_TE", // 0x12
+ "EFI_SECTION_DXE_DEPEX", // 0x13
+ "EFI_SECTION_VERSION", // 0x14
+ "EFI_SECTION_USER_INTERFACE", // 0x15
+ "EFI_SECTION_COMPATIBILITY16", // 0x16
+ "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17
+ "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18
+ "EFI_SECTION_RAW", // 0x19
+ NULL, // 0x1A
+ "EFI_SECTION_PEI_DEPEX", // 0x1B
+ "EFI_SECTION_SMM_DEPEX" // 0x1C
+};
+
+
+static CHAR8 *mFfsFileType[] = {
+ NULL, // 0x00
+ "EFI_FV_FILETYPE_RAW", // 0x01
+ "EFI_FV_FILETYPE_FREEFORM", // 0x02
+ "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03
+ "EFI_FV_FILETYPE_PEI_CORE", // 0x04
+ "EFI_FV_FILETYPE_DXE_CORE", // 0x05
+ "EFI_FV_FILETYPE_PEIM", // 0x06
+ "EFI_FV_FILETYPE_DRIVER", // 0x07
+ "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
+ "EFI_FV_FILETYPE_APPLICATION", // 0x09
+ "EFI_FV_FILETYPE_SMM", // 0x0A
+ "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
+ "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C
+ "EFI_FV_FILETYPE_SMM_CORE" // 0x0D
+ };
+
+FV_INFORMATION *
+LibInitializeFvStruct (
+ FV_INFORMATION *Fv
+)
+{
+ UINT32 Index;
+
+ if (Fv == NULL) {
+ return NULL;
+ }
+
+ memset (Fv, '\0', sizeof (FV_INFORMATION));
+
+ for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index ++) {
+ memset (Fv->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
+ memset (Fv->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
+
+ Fv->FfsAttuibutes[Index].IsLeaf = TRUE;
+ Fv->FfsAttuibutes[Index].TotalSectionNum = 0;
+ }
+
+ Fv->PatchData = NULL;
+ Fv->EncapData = NULL;
+ Fv->FvNext = NULL;
+ Fv->FvLevel = 0;
+ Fv->IsBfvFlag = FALSE;
+ Fv->IsInputFvFlag = FALSE;
+
+ return Fv;
+}
+
+/**
+ Generate the unique template filename.
+**/
+CHAR8 *
+GenTempFile (
+ VOID
+ )
+{
+ CHAR8 *TemString;
+ TemString = NULL;
+#ifndef __GNUC__
+ TemString = CloneString (tmpnam (NULL));
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ TemString = CloneString(tmp);
+ close(Fdtmp);
+#endif
+ return TemString;
+}
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+)
+{
+ FIRMWARE_DEVICE *LocalFdData;
+ UINT16 Index;
+ CHAR8 Ffs2Guid[16];
+ CHAR8 SignatureCheck[4];
+ CHAR8 Signature[5] = "_FVH";
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *NewFoundFv;
+ BOOLEAN FirstMatch;
+ UINT32 FdSize;
+ UINT16 FvCount;
+ VOID *FdBuffer;
+ VOID *FdBufferOri;
+ UINT32 Count;
+
+
+ CurrentFv = NULL;
+ NewFoundFv = NULL;
+ FdBuffer = NULL;
+ FdBufferOri = NULL;
+ FirstMatch = TRUE;
+ Index = 0;
+ FdSize = 0;
+ FvCount = 0;
+ Count = 0;
+ LocalFdData = NULL;
+
+ if (InputFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Find each FVs in the FD
+ //
+
+ fseek(InputFile,0,SEEK_SET);
+ fseek(InputFile,0,SEEK_END);
+
+ FdSize = ftell(InputFile);
+
+ fseek(InputFile,0,SEEK_SET);
+ //
+ // Create an FD structure to store useful information.
+ //
+ LocalFdData = (FIRMWARE_DEVICE *) calloc (sizeof (FIRMWARE_DEVICE), sizeof(UINT8));
+ if (LocalFdData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ LocalFdData->Fv = (FV_INFORMATION *) calloc (sizeof (FV_INFORMATION), sizeof(UINT8));
+ if (LocalFdData->Fv == NULL) {
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ LibInitializeFvStruct (LocalFdData->Fv);
+
+ //
+ // Readout the FD file data to buffer.
+ //
+ FdBuffer = malloc (FdSize);
+
+ if (FdBuffer == NULL) {
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (FdBuffer, 1, FdSize, InputFile) != FdSize) {
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_ABORTED;
+ }
+
+ FdBufferOri = FdBuffer;
+
+ for (Count=0; Count < FdSize - 4; Count++) {
+ //
+ // Copy 4 bytes of fd data to check the _FVH signature
+ //
+ memcpy (SignatureCheck, FdBuffer, 4);
+ FdBuffer =(UINT8 *)FdBuffer + 4;
+
+ if (strncmp(SignatureCheck, Signature, 4) == 0){
+ //
+ // Still need to determine the FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER equal to
+ // EFI_FIRMWARE_FILE_SYSTEM2_GUID.
+ // Turn back 28 bytes to find the GUID.
+ //
+ FdBuffer = (UINT8 *)FdBuffer - 28;
+ memcpy (Ffs2Guid, FdBuffer, 16);
+
+ //
+ // Compare GUID.
+ //
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem2Guid[Index]) {
+ break;
+ }
+ }
+ if (Index != 16) {
+ for (Index = 0; Index < 16; Index ++) {
+ if (Ffs2Guid[Index] != mFirmwareFileSystem3Guid[Index]) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Point to the original address
+ //
+ FdBuffer = (UINT8 *)FdBuffer + 28;
+
+ //
+ // Here we found an FV.
+ //
+ if (Index == 16) {
+ if (FirstMatch) {
+ LocalFdData->Fv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri) - 0x2c;
+ CurrentFv = LocalFdData->Fv;
+ CurrentFv->FvNext = NULL;
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(CurrentFv->FvName, "FV%d", FvCount);
+
+ FirstMatch = FALSE;
+ } else {
+ NewFoundFv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION));
+ if (NULL == NewFoundFv) {
+ free (LocalFdData->Fv);
+ free (LocalFdData);
+ free (FdBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LibInitializeFvStruct (NewFoundFv);
+
+ //
+ // Need to turn back 0x2c bytes
+ //
+ NewFoundFv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri) - 0x2c;
+
+ //
+ // Store the FV name by found sequence
+ //
+ sprintf(NewFoundFv->FvName, "FV%d", FvCount);
+
+ //
+ // Value it to NULL for found FV usage.
+ //
+ NewFoundFv->FvNext = NULL;
+ CurrentFv->FvNext = NewFoundFv;
+
+ //
+ // Make the CurrentFv point to next FV.
+ //
+ CurrentFv = CurrentFv->FvNext;
+ }
+
+ FvCount ++;
+ Index = 0;
+ }
+
+ }
+
+ //
+ // We need to turn back 3 bytes.
+ //
+ FdBuffer = (UINT8 *)FdBuffer - 3;
+ }
+
+ LocalFdData->Size = FdSize;
+
+ *FdData = LocalFdData;
+
+ free (FdBufferOri);
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+
+ UINTN BytesRead;
+ UINT32 Size;
+ EFI_FV_BLOCK_MAP_ENTRY BlockMap;
+
+ BytesRead = 0;
+ Size = 0;
+
+ if (InputFile == NULL || FvSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), SEEK_CUR);
+ do {
+ fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
+ BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+
+ if (BlockMap.NumBlocks != 0) {
+ Size += BlockMap.NumBlocks * BlockMap.Length;
+ }
+ } while (!(BlockMap.NumBlocks == 0 && BlockMap.Length == 0));
+
+
+ *FvSize = Size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Expands the 3 byte size commonly used in Firmware Volume data structures
+
+ @param[in] Size - Address of the 3 byte array representing the size
+
+ @return UINT32
+
+**/
+UINT32
+FvBufExpand3ByteSize (
+ IN VOID* Size
+ )
+{
+ return (((UINT8*)Size)[2] << 16) +
+ (((UINT8*)Size)[1] << 8) +
+ ((UINT8*)Size)[0];
+}
+
+/**
+
+ Clears out all files from the Fv buffer in memory
+
+ @param[in] Fv - Address of the Fv in memory
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+FvBufGetSize (
+ IN VOID *Fv,
+ OUT UINTN *Size
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FV_BLOCK_MAP_ENTRY *blk;
+
+ *Size = 0;
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ blk = hdr->BlockMap;
+
+ while (blk->Length != 0 || blk->NumBlocks != 0) {
+ *Size = *Size + (blk->Length * blk->NumBlocks);
+ if (*Size >= 0x40000000) {
+ //
+ // If size is greater than 1GB, then assume it is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+ blk++;
+ }
+
+ if (*Size == 0) {
+ //
+ // If size is 0, then assume the volume is corrupted
+ //
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+
+ Iterates through the files contained within the firmware volume
+
+ @param[in] Fv - Address of the Fv in memory
+ @param[in] Key - Should be 0 to get the first file. After that, it should be
+ passed back in without modifying it's contents to retrieve
+ subsequent files.
+ @param[in] File- Output file pointer
+ File == NULL - invalid parameter
+ otherwise - *File will be update to the location of the file
+
+ @return EFI_STATUS
+ EFI_NOT_FOUND
+ EFI_VOLUME_CORRUPTED
+
+**/
+EFI_STATUS
+FvBufFindNextFile (
+ IN VOID *Fv,
+ IN OUT UINTN *Key,
+ OUT VOID **File
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *hdr;
+ EFI_FFS_FILE_HEADER *fhdr;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN fsize;
+ EFI_STATUS Status;
+ UINTN fvSize;
+
+ hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
+ fhdr = NULL;
+
+ if (Fv == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FvBufGetSize (Fv, &fvSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (*Key == 0) {
+ if (hdr->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) hdr + hdr->ExtHeaderOffset);
+ *Key = (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSize;
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8);
+ } else {
+ *Key = hdr->HeaderLength;
+ }
+ }
+
+ FvbAttributes = hdr->Attributes;
+
+ for(
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8);
+ (*Key + sizeof (*fhdr)) < fvSize;
+ *Key = (UINTN)ALIGN_POINTER (*Key, 8)
+ ) {
+ fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
+ fsize = GetFfsFileLength (fhdr);
+ if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_VALID
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_HEADER_INVALID
+ )
+ ) {
+ *Key = *Key + 1;
+ continue;
+ } else if(
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_MARKED_FOR_UPDATE
+ ) ||
+ EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DELETED
+ )
+ ) {
+ *Key = *Key + fsize;
+ continue;
+ } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
+ FvbAttributes,
+ fhdr->State,
+ EFI_FILE_DATA_VALID
+ )
+ ) {
+ *File = (UINT8*)hdr + *Key;
+ *Key = *Key + fsize;
+ return EFI_SUCCESS;
+ }
+
+ *Key = *Key + 1;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/*
+ Generate the leaf FFS files.
+
+*/
+EFI_STATUS
+LibGenFfsFile (
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ErasePolarity
+)
+{
+ UINT32 FfsFileSize;
+ CHAR8 *FfsFileName;
+ FILE *FfsFile;
+ CHAR8 *TempDir;
+ CHAR8 TempBuf[_MAX_PATH];
+
+ FfsFileSize = 0;
+ FfsFileName = NULL;
+ FfsFile = NULL;
+ TempDir = NULL;
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ FfsFileName = (CHAR8 *) malloc (_MAX_PATH);
+ if (NULL == FfsFileName) {
+ return EFI_ABORTED;
+ }
+ memset (FfsFileName, '\0', _MAX_PATH);
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ sprintf (
+ TempBuf,
+ "-Num%d-%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X-Level%d",
+ *FfsCount,
+ (unsigned) CurrentFile->Name.Data1,
+ CurrentFile->Name.Data2,
+ CurrentFile->Name.Data3,
+ CurrentFile->Name.Data4[0],
+ CurrentFile->Name.Data4[1],
+ CurrentFile->Name.Data4[2],
+ CurrentFile->Name.Data4[3],
+ CurrentFile->Name.Data4[4],
+ CurrentFile->Name.Data4[5],
+ CurrentFile->Name.Data4[6],
+ CurrentFile->Name.Data4[7],
+ Level
+ );
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) + strlen(TempBuf) > _MAX_PATH - 1) {
+ free(FfsFileName);
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strcpy (FfsFileName, TempDir);
+ strncat (FfsFileName, OS_SEP_STR, _MAX_PATH - strlen (FfsFileName) - 1);
+ strncat (FfsFileName, CurrentFv->FvName, _MAX_PATH - strlen (FfsFileName) - 1);
+ strncat (FfsFileName, TempBuf, _MAX_PATH - strlen (FfsFileName) - 1);
+
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].FfsName, FfsFileName, strlen(FfsFileName));
+
+ //
+ // Update current FFS files file state.
+ //
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ FfsFile = fopen (FfsFileName, "wb+");
+ if (FfsFile == NULL) {
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) != FfsFileSize) {
+ fclose(FfsFile);
+ free(FfsFileName);
+ return EFI_ABORTED;
+ }
+
+ fclose(FfsFile);
+ free(FfsFileName);
+ FfsFileName = NULL;
+
+ CurrentFv->FfsNumbers = *FfsCount;
+
+ *FfsCount += 1;
+
+ if (ErasePolarity) {
+ CurrentFile->State = (UINT8)~(CurrentFile->State);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+BOOLEAN
+LibCheckPadFfsContainFvNameGuid (
+ IN FV_INFORMATION *CurrentFv,
+ IN EFI_FFS_FILE_HEADER2 *CurrentFile
+)
+{
+ UINT32 FfsFileSize;
+ UINT32 FfsDataSize;
+ EFI_GUID *FfsData;
+ ENCAP_INFO_DATA *LocalEncapData;
+
+ LocalEncapData = NULL;
+
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsDataSize = FfsFileSize - GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsData = (EFI_GUID *) ((INT8 *)CurrentFile + GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile));
+
+ if (FfsDataSize == 0) {
+ return TRUE;
+ }
+
+ LocalEncapData = CurrentFv->EncapData;
+
+ do {
+ if (LocalEncapData->FvExtHeader != NULL) {
+ if (CompareGuid(FfsData, &LocalEncapData->FvExtHeader->FvName) == 0) {
+ return TRUE;
+ }
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ } while (LocalEncapData->NextNode != NULL);
+
+ return FALSE;
+}
+
+BOOLEAN
+LibCheckPadFfsNotNull (
+ IN EFI_FFS_FILE_HEADER2 *CurrentFile
+)
+{
+ UINT32 FfsFileSize;
+ UINT32 FfsDataSize;
+ INT8 *FfsData;
+
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsDataSize = FfsFileSize - GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FfsData = (INT8 *)CurrentFile + GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ if (FfsDataSize == 0) {
+ return FALSE;
+ }
+
+ while (FfsDataSize > 0) {
+ if (((FfsData[FfsDataSize-1]) & 0xFF) != 0xFF) {
+ return TRUE;
+ }
+ FfsDataSize--;
+ }
+
+ return FALSE;
+}
+
+/**
+ Find a maximum length of free space in PAD FFS of Bfv.
+
+ @PadFfsHeader - The header of PAD FFS file
+
+ @return The length of free space
+
+**/
+UINT32
+GetBfvMaxFreeSpace (
+ IN EFI_FFS_FILE_HEADER2 *PadFfsHeader
+ )
+{
+ UINT32 FfsSize;
+ UINT32 Count;
+ UINT32 Index;
+ UINT32 MaxSize;
+ UINT32 HeaderSize;
+
+ Index = 0;
+ MaxSize = 0;
+
+ if (PadFfsHeader == NULL) {
+ return MaxSize;
+ }
+
+ FfsSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) PadFfsHeader);
+ HeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) PadFfsHeader);
+
+ for (Count = HeaderSize; Count < FfsSize; Count++) {
+ if (((((INT8 *)PadFfsHeader)[Count]) & 0xFF) == 0xFF) {
+ Index++;
+ } else {
+ if (Index > MaxSize) {
+ MaxSize = Index;
+ }
+ Index = 0;
+ }
+ }
+ return MaxSize;
+}
+
+
+/**
+
+ Get the Offset and data of PAD FFS file in FV file.
+ This function should be only called for find an PAD FFS contain additional data
+ (usually will contain FIT table data or reset vector.)
+
+ BFV:
+ ---------------------- <- Low
+ | |
+ | |
+ -----------------------
+ | FFSs ... |
+ -----------------------
+ | |
+ | |
+ -----------------------
+ | PAD FFS file |
+ | |
+ | reset vector |
+ | |
+ | FIT table |
+ -----------------------
+ | SEC CORE | <- High
+ -----------------------
+
+**/
+
+EFI_STATUS
+LibFindResetVectorAndFitTableData(
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvImage,
+ IN EFI_FFS_FILE_HEADER2 *CurrentFile,
+ IN OUT FV_INFORMATION *CurrentFv
+)
+{
+ UINT32 Count1;
+ UINT32 Count2;
+ UINT32 FfsFileSize;
+ BOOLEAN FfsFoundFlag;
+ UINT32 FfsOffset;
+ UINT32 DataOffset;
+ UINT32 HeaderSize;
+ PATCH_DATA_PAD_FFS *LocalPatchData;
+
+ FfsFileSize = 0;
+ Count1 = 0;
+ Count2 = 0;
+ FfsOffset = 0;
+ DataOffset = 0;
+ FfsFoundFlag = FALSE;
+ LocalPatchData = NULL;
+
+ if (CurrentFv == NULL || CurrentFile == NULL || FvImage == NULL) {
+ return EFI_ABORTED;
+ }
+
+ FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ HeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ for (Count1=0; Count1 < (FvImage->FvLength - FfsFileSize); Count1 ++) {
+ for (Count2=0; Count2 < FfsFileSize; Count2 ++) {
+ if (((INT8*)FvImage)[Count1 + Count2] != ((INT8 *) CurrentFile)[Count2]){
+ break;
+ }
+ }
+ if (Count2 == FfsFileSize) {
+ FfsFoundFlag = TRUE;
+ FfsOffset = Count1;
+ break;
+ }
+ }
+
+ if (FfsFoundFlag) {
+ //
+ // Find data in FFS file;
+ // Will skip FFS header;
+ //
+ for (Count1 = HeaderSize; Count1 < FfsFileSize; Count1++) {
+ if (((((INT8 *)CurrentFile)[Count1]) & 0xFF) != 0xFF) {
+ DataOffset = FfsOffset + Count1;
+ break;
+ }
+ }
+
+ if (CurrentFv->PatchData == NULL) {
+ //
+ // First time found data.
+ //
+ CurrentFv->PatchData = (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATCH_DATA_PAD_FFS));
+ if (CurrentFv->PatchData == NULL) {
+ return EFI_ABORTED;
+ }
+
+ CurrentFv->PatchData->Offset = DataOffset;
+ CurrentFv->PatchData->Data = malloc(FfsFileSize - Count1);
+ CurrentFv->PatchData->Length = FfsFileSize - Count1;
+ CurrentFv->PatchData->NextNode = NULL;
+
+ if (CurrentFv->PatchData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (CurrentFv->PatchData->Data, (INT8 *)CurrentFile + Count1, FfsFileSize - Count1);
+ } else {
+ LocalPatchData = CurrentFv->PatchData;
+
+ while (LocalPatchData->NextNode != NULL) {
+ LocalPatchData = LocalPatchData->NextNode;
+ }
+
+ LocalPatchData = (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATCH_DATA_PAD_FFS));
+
+ if (LocalPatchData == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalPatchData->Offset = DataOffset;
+ LocalPatchData->Data = malloc(FfsFileSize - Count1);
+ LocalPatchData->Length = FfsFileSize - Count1;
+ LocalPatchData->NextNode = NULL;
+
+ if (LocalPatchData->Data == NULL) {
+ free (LocalPatchData);
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalPatchData->Data, (INT8 *)CurrentFile + Count1, FfsFileSize - Count1);
+ while (CurrentFv->PatchData->NextNode != NULL) {
+ CurrentFv->PatchData = CurrentFv->PatchData->NextNode;
+ }
+ CurrentFv->PatchData->NextNode = LocalPatchData;
+ }
+
+ } else {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Construct a set of blank chars based on the number.
+
+ @param[in] Count The number of blank chars.
+
+ @return A string contained the blank chars.
+
+*/
+CHAR8 *
+LibConstructBlankChar (
+ IN UINT8 Count
+)
+{
+ CHAR8 *RetStr;
+ UINT8 Index;
+
+ Index = 0;
+ RetStr = NULL;
+
+ RetStr = (CHAR8 *) malloc (Count +1);
+
+ if (NULL == RetStr) {
+ return NULL;
+ }
+
+ memset (RetStr , '\0', Count + 1);
+
+ for (Index=0; Index <= Count -1; Index ++) {
+ RetStr[Index] = ' ';
+ }
+
+ return RetStr;
+
+}
+
+VOID
+Unicode2AsciiString (
+ IN CHAR16 *Source,
+ OUT CHAR8 *Destination
+ )
+ /*++
+
+ Routine Description:
+
+ Convert a null-terminated unicode string to a null-terminated ascii string.
+
+ Arguments:
+
+ Source - The pointer to the null-terminated input unicode string.
+ Destination - The pointer to the null-terminated output ascii string.
+
+ Returns:
+
+ N/A
+
+ --*/
+{
+ while (*Source != '\0') {
+ *(Destination++) = (CHAR8) *(Source++);
+ }
+ //
+ // End the ascii with a NULL.
+ //
+ *Destination = '\0';
+}
+
+
+/**
+
+ Parses EFI Sections, if the view flag turn on, then will collect FFS section information
+ and extract FFS files.
+
+ @param[in] SectionBuffer - Buffer containing the section to parse.
+ @param[in] BufferLength - Length of SectionBuffer
+ @param[in, out] CurrentFv
+ @param[in] FvName
+ @param[in] CurrentFile
+ @param[in] Level
+ @param[in, out] FfsCount
+ @param[in] ViewFlag
+ @param[in] ErasePolarity
+
+ @retval EFI_SECTION_ERROR - Problem with section parsing.
+ (a) compression errors
+ (b) unrecognized section
+ @retval EFI_UNSUPPORTED - Do not know how to parse the section.
+ @retval EFI_SUCCESS - Section successfully parsed.
+ @retval EFI_OUT_OF_RESOURCES - Memory allocation failed.
+
+--*/
+EFI_STATUS
+LibParseSection (
+ UINT8 *SectionBuffer,
+ UINT32 BufferLength,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ViewFlag,
+ BOOLEAN ErasePolarity,
+ BOOLEAN FfsGeneratedFlag
+ )
+{
+ UINT32 ParsedLength;
+ UINT8 *Ptr;
+ UINT32 SectionLength;
+ UINT32 UiSectionLength;
+ EFI_SECTION_TYPE Type;
+ EFI_STATUS Status;
+ CHAR8 *ExtractionTool;
+ CHAR8 *ToolInputFile;
+ CHAR8 *ToolOutputFile;
+ CHAR8 *SystemCommand;
+ UINT8 *ToolOutputBuffer;
+ UINT32 ToolOutputLength;
+ CHAR16 *UIName;
+ UINT32 UINameSize;
+ BOOLEAN HasDepexSection;
+ UINT32 NumberOfSections;
+ BOOLEAN IsFfsGenerated;
+ ENCAP_INFO_DATA *LocalEncapData;
+ CHAR8 *BlankChar;
+ UINT8 *UncompressedBuffer;
+ UINT32 UncompressedLength;
+ UINT8 *CompressedBuffer;
+ UINT32 CompressedLength;
+ UINT8 CompressionType;
+ DECOMPRESS_FUNCTION DecompressFunction;
+ GETINFO_FUNCTION GetInfoFunction;
+ UINT32 DstSize;
+ UINT32 ScratchSize;
+ UINT8 *ScratchBuffer;
+ BOOLEAN EncapDataNeedUpdata;
+ CHAR8 *TempDir;
+ CHAR8 *ToolInputFileFullName;
+ CHAR8 *ToolOutputFileFullName;
+ UINT8 LargeHeaderOffset;
+ CHAR8 *UIFileName;
+ CHAR8 *ToolInputFileName;
+ CHAR8 *ToolOutputFileName;
+
+ ParsedLength = 0;
+ ToolOutputLength = 0;
+ UINameSize = 0;
+ NumberOfSections = 0;
+ UncompressedLength = 0;
+ CompressedLength = 0;
+ CompressionType = 0;
+ DstSize = 0;
+ ScratchSize = 0;
+ Ptr = NULL;
+ ExtractionTool = NULL;
+ ToolInputFile = NULL;
+ ToolOutputFile = NULL;
+ SystemCommand = NULL;
+ ToolOutputBuffer = NULL;
+ UIName = NULL;
+ LocalEncapData = NULL;
+ BlankChar = NULL;
+ UncompressedBuffer = NULL;
+ CompressedBuffer = NULL;
+ ScratchBuffer = NULL;
+ TempDir = NULL;
+ ToolInputFileFullName = NULL;
+ ToolOutputFileFullName = NULL;
+ ToolInputFileName = NULL;
+ ToolOutputFileName = NULL;
+ HasDepexSection = FALSE;
+ IsFfsGenerated = FfsGeneratedFlag;
+ EncapDataNeedUpdata = TRUE;
+ LargeHeaderOffset = 0;
+
+
+ while (ParsedLength < BufferLength) {
+ Ptr = SectionBuffer + ParsedLength;
+
+ SectionLength = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if (SectionLength == 0xffffff && Type == 0xff) {
+ ParsedLength += 4;
+ continue;
+ }
+ //
+ //If Size is 0xFFFFFF then ExtendedSize contains the size of the section.
+ //
+ if (SectionLength == 0xffffff) {
+ SectionLength = ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSize;
+ LargeHeaderOffset = sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+
+ switch (Type) {
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+ EncapDataNeedUpdata = TRUE;
+
+ Level ++;
+ NumberOfSections ++;
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdata = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_FV_SECTION;
+
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ //
+ LocalEncapData->Data = NULL;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ Status = LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, FfsCount, ViewFlag, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+ break;
+
+ case EFI_SECTION_COMPRESSION:
+ Level ++;
+ NumberOfSections ++;
+
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdata = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (EncapDataNeedUpdata) {
+ //
+ // Put in this is an FFS with FV section
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_COMPRESS_SECTION;
+
+ //
+ // Store the compress type
+ //
+ LocalEncapData->Data = malloc (sizeof (UINT8));
+
+ if (LocalEncapData->Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ //
+ // Process compressed section
+ //
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ UncompressedBuffer = NULL;
+ CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION) - LargeHeaderOffset;
+ UncompressedLength = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+
+ if (CompressedLength != UncompressedLength) {
+ printf ("Error. File is not compressed, but the compressed length does not match the uncompressed length.\n");
+ return EFI_SECTION_ERROR;
+ }
+
+ UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ GetInfoFunction = EfiGetInfo;
+ DecompressFunction = EfiDecompress;
+
+ CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset;
+
+ Status = GetInfoFunction (CompressedBuffer, CompressedLength, &DstSize, &ScratchSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+
+ if (DstSize != UncompressedLength) {
+ return EFI_SECTION_ERROR;
+ }
+
+ ScratchBuffer = malloc (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UncompressedBuffer = malloc (UncompressedLength);
+
+ if (UncompressedBuffer == NULL) {
+ free (ScratchBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Decompress the section.
+ //
+ Status = DecompressFunction (
+ CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ ScratchBuffer,
+ ScratchSize
+ );
+ free (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ free (UncompressedBuffer);
+ return EFI_SECTION_ERROR;
+ }
+ } else {
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection ( UncompressedBuffer,
+ UncompressedLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated);
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ //
+ // We need to deallocate Buffer
+ //
+ free (UncompressedBuffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ //
+ // Process GUID defined
+ // looks up the appropriate tool to use for extracting
+ // a GUID defined FV section.
+ //
+ Level ++;
+ NumberOfSections++;
+
+ EncapDataNeedUpdata = TRUE;
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdata = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ if (EncapDataNeedUpdata) {
+
+ //
+ // Put in this is an FFS with FV section
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_GUIDED_SECTION;
+
+ //
+ // We don't need additional data for encapsulate this FFS but type.
+ //
+
+ LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID));
+
+ if (LocalEncapData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid, sizeof (EFI_GUID));
+
+ LocalEncapData->FvExtHeader = NULL;
+ LocalEncapData->NextNode = NULL;
+ }
+
+ CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid
+ );
+
+ if ((((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
+ //
+ // Not require process, directly gets data.
+ //
+ Status = LibParseSection (
+ Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+ } else if (ExtractionTool != NULL) {
+
+ TempDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ free (ExtractionTool);
+ return EFI_ABORTED;
+ }
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ ToolInputFile = GenTempFile ();
+ ToolOutputFile = GenTempFile ();
+ ToolInputFileName = strrchr(ToolInputFile, OS_SEP);
+ ToolOutputFileName = strrchr(ToolOutputFile, OS_SEP);
+
+ ToolInputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolInputFileName) + 1);
+ if (ToolInputFileFullName == NULL) {
+ free (ExtractionTool);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ToolOutputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolOutputFileName) + 1);
+ if (ToolOutputFileFullName == NULL) {
+ free (ToolInputFileFullName);
+ free (ExtractionTool);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName);
+ sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileName);
+
+ //
+ // Construction 'system' command string
+ //
+ SystemCommand = malloc (
+ strlen (DECODE_STR) +
+ strlen (ExtractionTool) +
+ strlen (ToolInputFileFullName) +
+ strlen (ToolOutputFileFullName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ExtractionTool);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ DECODE_STR,
+ ExtractionTool,
+ ToolOutputFileFullName,
+ ToolInputFileFullName
+ );
+
+ Status = PutFileImage (
+ ToolInputFileFullName,
+ (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset
+ );
+
+ if (HasDepexSection) {
+ HasDepexSection = FALSE;
+ }
+
+ if (EFI_ERROR (Status)) {
+ free(SystemCommand);
+ free (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ return EFI_SECTION_ERROR;
+ }
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ SystemCommand = malloc (
+ strlen (DECODE_STR_ERR) +
+ strlen (ExtractionTool) +
+ strlen (ToolInputFileFullName) +
+ strlen (ToolOutputFileFullName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ free (ExtractionTool);
+ LibRmDir (TempDir);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ DECODE_STR_ERR,
+ ExtractionTool,
+ ToolOutputFileFullName,
+ ToolInputFileFullName
+ );
+ system (SystemCommand);
+ printf("Command failed: %s\n", SystemCommand);
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ LibRmDir (TempDir);
+ free(SystemCommand);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ free (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ return EFI_ABORTED;
+ }
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ free (SystemCommand);
+ remove (ToolInputFileFullName);
+ free (ToolInputFile);
+ free (ToolInputFileFullName);
+ ToolInputFile = NULL;
+ ToolInputFileFullName = NULL;
+
+
+ Status = GetFileImage (
+ ToolOutputFileFullName,
+ (CHAR8 **)&ToolOutputBuffer,
+ &ToolOutputLength
+ );
+ remove (ToolOutputFileFullName);
+ free (ToolOutputFile);
+ free (ToolOutputFileFullName);
+ ToolOutputFile = NULL;
+ ToolOutputFileFullName = NULL;
+
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+
+ Status = LibParseSection (
+ ToolOutputBuffer,
+ ToolOutputLength,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ IsFfsGenerated
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SECTION_ERROR;
+ }
+ } else {
+ //
+ // We don't know how to parse it now.
+ //
+ if (ExtractionTool != NULL) {
+ free (ExtractionTool);
+ ExtractionTool = NULL;
+ }
+ printf(" EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in %s file.\n", mGuidToolDefinition);
+ printf(" Its GUID is: ");
+ PrintGuid(&(((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->SectionDefinitionGuid));
+ return EFI_UNSUPPORTED;
+ }
+
+ break;
+
+ //
+ //Leaf sections
+ //
+ case EFI_SECTION_RAW:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PE32:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_PIC:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+
+ break;
+ case EFI_SECTION_TE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_COMPATIBILITY16:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ if (!IsFfsGenerated) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ IsFfsGenerated = TRUE;
+ }
+ }
+ break;
+
+ case EFI_SECTION_VERSION:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ break;
+ case EFI_SECTION_PEI_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ break;
+ case EFI_SECTION_DXE_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ break;
+ case EFI_SECTION_SMM_DEPEX:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ HasDepexSection = TRUE;
+ break;
+
+ case EFI_SECTION_USER_INTERFACE:
+ NumberOfSections ++;
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+ UiSectionLength = FvBufExpand3ByteSize (((EFI_USER_INTERFACE_SECTION *) Ptr)->CommonHeader.Size);
+ if (UiSectionLength == 0xffffff) {
+ UiSectionLength = ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonHeader.ExtendedSize;
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER2);
+ } else {
+ UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER);
+ }
+
+ UIName = (CHAR16 *) malloc (UINameSize + 2);
+ if (UIName != NULL) {
+ memset (UIName, '\0', UINameSize + 2);
+ if (UiSectionLength >= 0xffffff) {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameString, UINameSize);
+ } else {
+ memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UINameSize);
+ }
+ } else {
+ return EFI_ABORTED;
+ }
+
+ BlankChar = LibConstructBlankChar( CurrentFv->FvLevel * 2);
+ if (BlankChar == NULL) {
+ free (UIName);
+ return EFI_ABORTED;
+ }
+
+ if (ViewFlag) {
+ UIFileName = malloc (UINameSize + 2);
+ if (UIFileName == NULL) {
+ free(BlankChar);
+ free(UIName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Unicode2AsciiString (UIName, UIFileName);
+ fprintf(stdout, "%sFile \"%s\"\n", BlankChar, UIFileName);
+ free(UIFileName);
+ }
+
+ free (BlankChar);
+ BlankChar = NULL;
+
+ //
+ // If Ffs file has been generated, then the FfsCount should decrease 1.
+ //
+ if (IsFfsGenerated) {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UINameSize);
+ } else {
+ memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UINameSize);
+ }
+ HasDepexSection = FALSE;
+ free(UIName);
+ UINameSize = 0;
+
+ break;
+ default:
+ break;
+ }
+
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+
+ if (ParsedLength < BufferLength) {
+ return EFI_SECTION_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Add function description
+
+ FvImage - add argument description
+ FileHeader - add argument description
+ ErasePolarity - add argument description
+
+ EFI_SUCCESS - Add description for return value
+ EFI_ABORTED - Add description for return value
+
+**/
+EFI_STATUS
+LibGetFileInfo (
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage,
+ EFI_FFS_FILE_HEADER2 *CurrentFile,
+ BOOLEAN ErasePolarity,
+ FV_INFORMATION *CurrentFv,
+ CHAR8 *FvName,
+ UINT8 Level,
+ UINT32 *FfsCount,
+ BOOLEAN ViewFlag
+ )
+{
+ UINT32 FileLength;
+ UINT8 FileState;
+ UINT8 Checksum;
+ EFI_FFS_FILE_HEADER2 BlankHeader;
+ EFI_STATUS Status;
+ ENCAP_INFO_DATA *LocalEncapData;
+ BOOLEAN EncapDataNeedUpdateFlag;
+ UINT32 FfsFileHeaderSize;
+
+ Status = EFI_SUCCESS;
+
+ LocalEncapData = NULL;
+ EncapDataNeedUpdateFlag = TRUE;
+
+ FfsFileHeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+ FileLength = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+ //
+ // Check if we have free space
+ //
+ if (ErasePolarity) {
+ memset (&BlankHeader, -1, FfsFileHeaderSize);
+ } else {
+ memset (&BlankHeader, 0, FfsFileHeaderSize);
+ }
+
+ //
+ // Is this FV blank?
+ //
+ if (memcmp (&BlankHeader, CurrentFile, FfsFileHeaderSize) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Print file information.
+ //
+ FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)CurrentFile);
+
+ if (FileState == EFI_FILE_DATA_VALID) {
+ //
+ // Calculate header checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize);
+ Checksum = (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum.File);
+ Checksum = (UINT8) (Checksum - CurrentFile->State);
+ if (Checksum != 0) {
+ return EFI_ABORTED;
+ }
+
+ if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) {
+ //
+ // Calculate file checksum
+ //
+ Checksum = CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFileHeaderSize), FileLength - FfsFileHeaderSize);
+ Checksum = Checksum + CurrentFile->IntegrityCheck.Checksum.File;
+ if (Checksum != 0) {
+ return EFI_ABORTED;
+ }
+ } else {
+ if (CurrentFile->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+ return EFI_ABORTED;
+ }
+ }
+ } else {
+ return EFI_ABORTED;
+ }
+
+ Level += 1;
+
+ if (CurrentFile->Type != EFI_FV_FILETYPE_ALL) {
+
+ //
+ // Put in encapsulate data information.
+ //
+ LocalEncapData = CurrentFv->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ EncapDataNeedUpdateFlag = FALSE;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (EncapDataNeedUpdateFlag) {
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_FFS;
+ LocalEncapData->FvExtHeader = NULL;
+
+ //
+ // Store the header of FFS file.
+ //
+ LocalEncapData->Data = malloc (FfsFileHeaderSize);
+ if (LocalEncapData->Data == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+
+ LocalEncapData->NextNode = NULL;
+ }
+
+ if ( CurrentFile->Type == EFI_FV_FILETYPE_FREEFORM ){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag) {
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ }else if ( CurrentFile->Type == EFI_FV_FILETYPE_RAW){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ if (!ViewFlag){
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ } else if ( CurrentFile->Type == EFI_FV_FILETYPE_SECURITY_CORE){
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ //
+ // If an FV contain SECCORE, this FV will be considered as BFV.
+ //
+ CurrentFv->IsBfvFlag = TRUE;
+ if (!ViewFlag){
+ LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ }
+ } else if( CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD){
+ //
+ // First check whether the FFS file contain FvExtended FvNameGuid information.
+ //
+ if (!LibCheckPadFfsContainFvNameGuid (CurrentFv, CurrentFile)) {
+ //
+ // Then check whether the PAD file have no additional data or not.
+ //
+ if (LibCheckPadFfsNotNull (CurrentFile)) {
+ CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+ //
+ // Get the size of PAD in BFV
+ //
+ PadSizeOfBfv = GetBfvMaxFreeSpace (CurrentFile);
+ if (!ViewFlag){
+ //
+ //LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+ //
+ Status = LibFindResetVectorAndFitTableData (FvImage, CurrentFile, CurrentFv);
+ if (EFI_ERROR (Status)) {
+ printf ("Find reset vector and FIT table data failed. \n");
+ return EFI_ABORTED;
+ }
+ }
+ }
+ }
+ } else {
+ //
+ // All other files have sections
+ //
+ Status = LibParseSection (
+ (UINT8 *) ((UINTN) CurrentFile + FfsFileHeaderSize),
+ FileLength - FfsFileHeaderSize,
+ CurrentFv,
+ FvName,
+ CurrentFile,
+ Level,
+ FfsCount,
+ ViewFlag,
+ ErasePolarity,
+ FALSE
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ printf ("Error while parse the FFS file.\n");
+ return EFI_ABORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get firmware information. Including the FV headers,
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN UINT32 *FfsCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfFiles;
+ BOOLEAN ErasePolarity;
+ UINTN FvSize;
+ EFI_FFS_FILE_HEADER2 *CurrentFile;
+ UINTN Key;
+ ENCAP_INFO_DATA *LocalEncapData;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHdrPtr;
+
+ NumberOfFiles = 0;
+ Key = 0;
+ LocalEncapData = NULL;
+ CurrentFile = NULL;
+
+ Level += 1;
+ CurrentFv->FvLevel += 1;
+
+ Status = FvBufGetSize (Fv, &FvSize);
+
+ ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE;
+
+ if (!IsChildFv) {
+ //
+ // Write FV header information into CurrentFv struct.
+ //
+ CurrentFv->FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (CurrentFv->FvHeader == NULL) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV Header information
+ //
+ memcpy (CurrentFv->FvHeader, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ CurrentFv->FvExtHeader = NULL;
+
+ //
+ // Exist Extend FV header.
+ //
+ if (CurrentFv->FvHeader->ExtHeaderOffset != 0){
+ CurrentFv->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
+
+ if (CurrentFv->FvExtHeader == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy (CurrentFv->FvExtHeader, (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset), sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
+ if (mFvGuidIsSet) {
+ if (CompareGuid (&CurrentFv->FvExtHeader->FvName, &mFvNameGuid) == 0) {
+ CurrentFv->IsInputFvFlag = TRUE;
+ }
+ }
+
+ }
+
+ }
+
+ //
+ // Put encapsulate information into structure.
+ //
+ if (CurrentFv->EncapData == NULL && !IsChildFv) {
+ //
+ // First time in, the root FV
+ //
+ CurrentFv->EncapData = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (CurrentFv->EncapData == NULL) {
+ return EFI_ABORTED;
+ }
+ CurrentFv->EncapData->FvExtHeader = NULL;
+ CurrentFv->EncapData->Level = Level;
+ CurrentFv->EncapData->Type = BFM_ENCAP_TREE_FV;
+ CurrentFv->EncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (CurrentFv->EncapData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset);
+ CurrentFv->EncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize);
+
+ if (CurrentFv->EncapData->FvExtHeader == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(CurrentFv->EncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ if (mFvGuidIsSet) {
+ if (CompareGuid (&CurrentFv->EncapData->FvExtHeader->FvName, &mFvNameGuid) == 0) {
+ CurrentFv->IsInputFvFlag = TRUE;
+ }
+ }
+
+ }
+
+ CurrentFv->EncapData->NextNode = NULL;
+
+ } else if (CurrentFv->EncapData == NULL) {
+ return EFI_ABORTED;
+ } else if (IsChildFv) {
+
+ LocalEncapData = CurrentFv->EncapData;
+
+ while (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ //
+ // Construct the new ENCAP_DATA
+ //
+ LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+ if (LocalEncapData->NextNode == NULL) {
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = LocalEncapData->NextNode;
+
+ LocalEncapData->Level = Level;
+ LocalEncapData->Type = BFM_ENCAP_TREE_FV;
+ LocalEncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+ LocalEncapData->FvExtHeader = NULL;
+
+ if (LocalEncapData->Data == NULL) {
+ return EFI_ABORTED;
+ }
+
+ memcpy (LocalEncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset);
+ LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(ExtHdrPtr->ExtHeaderSize);
+
+ if (LocalEncapData->FvExtHeader == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Get the FV extended Header information
+ //
+ memcpy(LocalEncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize);
+ }
+
+ LocalEncapData->NextNode = NULL;
+
+ }
+
+
+ //
+ // Get the first file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ printf ("Failed to find the first file from Fv. \n");
+ return Status;
+ }
+
+ while (CurrentFile != NULL) {
+
+ //
+ // Increment the number of files counter
+ //
+ NumberOfFiles++;
+
+ //
+ // Store FFS file Header information
+ //
+ CurrentFv->FfsHeader[*FfsCount].Attributes = CurrentFile->Attributes;
+ CurrentFv->FfsHeader[*FfsCount].IntegrityCheck = CurrentFile->IntegrityCheck;
+ CurrentFv->FfsHeader[*FfsCount].Name = CurrentFile->Name;
+ CurrentFv->FfsHeader[*FfsCount].Size[0] = CurrentFile->Size[0];
+ CurrentFv->FfsHeader[*FfsCount].Size[1] = CurrentFile->Size[1];
+ CurrentFv->FfsHeader[*FfsCount].Size[2] = CurrentFile->Size[2];
+ CurrentFv->FfsHeader[*FfsCount].State = CurrentFile->State;
+ CurrentFv->FfsHeader[*FfsCount].Type = CurrentFile->Type;
+ CurrentFv->FfsHeader[*FfsCount].ExtendedSize = CurrentFile->ExtendedSize;
+
+ //
+ // Display info about this file
+ //
+ Status = LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, FvName, Level, FfsCount, ViewFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the next file
+ //
+ Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+ if (Status == EFI_NOT_FOUND) {
+ CurrentFile = NULL;
+ } else if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+LibGenExtFile(
+ CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtPtr,
+ FILE *InfFile
+)
+{
+ CHAR8 *TempDir;
+ FILE *ExtFile;
+ CHAR8 OutputExtFile[_MAX_PATH];
+ CHAR8 Line[512];
+ size_t Len;
+
+ TempDir = NULL;
+
+ TempDir = getcwd(NULL, _MAX_PATH);
+
+ if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+
+ strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) - 1);
+ strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) - 1);
+ mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ sprintf(
+ Line,
+ "%c%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X%d.ext",
+ OS_SEP,
+ (unsigned)ExtPtr->FvName.Data1,
+ ExtPtr->FvName.Data2,
+ ExtPtr->FvName.Data3,
+ ExtPtr->FvName.Data4[0],
+ ExtPtr->FvName.Data4[1],
+ ExtPtr->FvName.Data4[2],
+ ExtPtr->FvName.Data4[3],
+ ExtPtr->FvName.Data4[4],
+ ExtPtr->FvName.Data4[5],
+ ExtPtr->FvName.Data4[6],
+ ExtPtr->FvName.Data4[7],
+ ExtPtr->ExtHeaderSize
+ );
+ if (strlen (TempDir) + strlen (Line) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strncpy (OutputExtFile, TempDir, _MAX_PATH - 1);
+ OutputExtFile[_MAX_PATH - 1] = 0;
+ strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1);
+
+
+ ExtFile = fopen(OutputExtFile, "wb+");
+ if (ExtFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) != ExtPtr->ExtHeaderSize) {
+ fclose(ExtFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(ExtFile);
+
+ strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME = ");
+ if (strlen (Line) + strlen (OutputExtFile) + 1 > sizeof(Line) / sizeof (CHAR8) - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strncat (Line, OutputExtFile, sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1);
+ Len = strlen(Line);
+ if (fwrite(Line, 1, Len, InfFile) != Len) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ )
+{
+ UINT32 OccupiedSize;
+
+ OccupiedSize = ActualSize;
+ while ((OccupiedSize & (Alignment - 1)) != 0) {
+ OccupiedSize++;
+ }
+
+ return OccupiedSize;
+}
+
+/**
+ Converts ASCII characters to Unicode.
+ Assumes that the Unicode characters are only these defined in the ASCII set.
+
+ String - Pointer to string that is written to FILE.
+ UniString - Pointer to unicode string
+
+ The address to the ASCII string - same as AsciiStr.
+
+**/
+VOID
+LibAscii2Unicode (
+ IN CHAR8 *String,
+ OUT CHAR16 *UniString
+ )
+{
+ while (*String != '\0') {
+ *(UniString++) = (CHAR16) *(String++);
+ }
+ //
+ // End the UniString with a NULL.
+ //
+ *UniString = '\0';
+}
+
+
+EFI_STATUS
+LibCreateGuidedSectionOriginalData(
+ IN CHAR8* FileIn,
+ IN CHAR8* ToolName,
+ IN CHAR8* FileOut
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+ if (FileIn == NULL ||
+ ToolName == NULL ||
+ FileOut == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SystemCommand = malloc (
+ strlen (ENCODE_STR) +
+ strlen (FileIn) +
+ strlen (ToolName) +
+ strlen (FileOut) +
+ 1
+ );
+
+ if (NULL == SystemCommand) {
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ ENCODE_STR,
+ ToolName,
+ FileIn,
+ FileOut
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ SystemCommand = malloc (
+ strlen (ENCODE_STR_ERR) +
+ strlen (FileIn) +
+ strlen (ToolName) +
+ strlen (FileOut) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ ENCODE_STR_ERR,
+ ToolName,
+ FileIn,
+ FileOut
+ );
+ system (SystemCommand);
+ printf("Command failed: %s\n", SystemCommand);
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function convert the FV header's attribute to a string. The converted string
+ will be put into an INF file as the input of GenFV.
+
+ @param[in] Attr FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+ @retval EFI_OUT_OF_RESOURCES
+
+**/
+EFI_STATUS
+LibFvHeaderAttributeToStr (
+ IN EFI_FVB_ATTRIBUTES_2 Attr,
+ IN FILE* InfFile
+)
+{
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ LocalStr = (CHAR8 *) malloc (1024 * 4);
+
+ if (LocalStr == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', 1024 * 4);
+
+ if (Attr == 0 || InfFile == NULL) {
+ free (LocalStr);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ strncat (LocalStr, "[attributes] \n", sizeof("[attributes] \n"));
+
+ if (Attr & EFI_FVB2_READ_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_DISABLED_CAP = TRUE \n", sizeof ("EFI_READ_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_READ_ENABLED_CAP = TRUE \n", sizeof ("EFI_READ_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_STATUS) {
+ strncat (LocalStr, "EFI_READ_STATUS = TRUE \n", sizeof ("EFI_READ_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_DISABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_DISABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) {
+ strncat (LocalStr, "EFI_WRITE_ENABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_ENABLED_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_STATUS = TRUE \n", sizeof ("EFI_WRITE_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_CAP) {
+ strncat (LocalStr, "EFI_LOCK_CAP = TRUE \n", sizeof ("EFI_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_LOCK_STATUS = TRUE \n", sizeof ("EFI_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_STICKY_WRITE) {
+ strncat (LocalStr, "EFI_STICKY_WRITE = TRUE \n", sizeof ("EFI_STICKY_WRITE = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_MEMORY_MAPPED) {
+ strncat (LocalStr, "EFI_MEMORY_MAPPED = TRUE \n", sizeof ("EFI_MEMORY_MAPPED = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_ERASE_POLARITY) {
+ strncat (LocalStr, "EFI_ERASE_POLARITY = 1 \n", sizeof ("EFI_ERASE_POLARITY = 1 \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_CAP) {
+ strncat (LocalStr, "EFI_READ_LOCK_CAP = TRUE \n", sizeof ("EFI_READ_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_READ_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_CAP) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_CAP = TRUE \n", sizeof ("EFI_WRITE_LOCK_CAP = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_WRITE_LOCK_STATUS = TRUE \n", sizeof ("EFI_WRITE_LOCK_STATUS = TRUE \n"));
+ }
+
+ if (Attr & EFI_FVB2_LOCK_STATUS) {
+ strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n"));
+ }
+
+ //
+ // Alignment
+ //
+ if (Attr & EFI_FVB2_ALIGNMENT_1) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512 = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512K) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512K = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_4M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_8M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_16M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_32M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_64M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_128M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_256M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_512M) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512M = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_1G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1G = TRUE \n"));
+ } else if (Attr & EFI_FVB2_ALIGNMENT_2G) {
+ strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2G = TRUE \n"));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while write data to %p file. \n", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] BlockMap FV header's attribute.
+ @param[out] InfFile InfFile contain FV header attribute information.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibFvHeaderOptionToStr (
+ IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,
+ IN FILE* InfFile,
+ IN BOOLEAN IsRootFv
+)
+{
+ CHAR8 *LocalStr;
+ CHAR8 *BlockSize;
+ CHAR8 *NumOfBlocks;
+
+ LocalStr = NULL;
+ BlockSize = NULL;
+ NumOfBlocks = NULL;
+
+ if (BlockMap == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // This section will not over 1024 bytes and each line will never over 128 bytes.
+ //
+ LocalStr = (CHAR8 *) malloc (1024);
+ BlockSize = (CHAR8 *) malloc (128);
+ NumOfBlocks = (CHAR8 *) malloc (128);
+
+ if (LocalStr == NULL ||
+ BlockSize == NULL ||
+ NumOfBlocks == NULL) {
+ if (LocalStr != NULL) {
+ free (LocalStr);
+ }
+ if (BlockSize != NULL) {
+ free (BlockSize);
+ }
+ if (NumOfBlocks != NULL) {
+ free (NumOfBlocks);
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', 1024);
+ memset (BlockSize, '\0', 128);
+ memset (NumOfBlocks, '\0', 128);
+
+ strncat (LocalStr, "[options] \n", sizeof("[Options] \n"));
+
+ sprintf (BlockSize, "EFI_BLOCK_SIZE = 0x%x \n", BlockMap->Length);
+ strncat (LocalStr, BlockSize, strlen(BlockSize));
+
+ if (IsRootFv) {
+ sprintf (NumOfBlocks, "EFI_NUM_BLOCKS = 0x%x \n", BlockMap->NumBlocks);
+ strncat (LocalStr, NumOfBlocks, strlen(NumOfBlocks));
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ free (LocalStr);
+ free (BlockSize);
+ free (NumOfBlocks);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+ free (BlockSize);
+ free (NumOfBlocks);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function fill the FV inf files option field.
+
+ @param[in] FfsName Ffs file path/name.
+ @param[out] InfFile InfFile contain FV header attribute information
+ @param[in] FirstIn Is the first time call this function? If yes, should create [files] section.
+
+ @retval EFI_SUCCESS.
+ @retval EFI_INVLID_PARAMETER
+
+**/
+EFI_STATUS
+LibAddFfsFileToFvInf (
+ IN CHAR8 *FfsName,
+ IN FILE* InfFile,
+ IN BOOLEAN FirstIn
+)
+{
+
+ CHAR8 *LocalStr;
+
+ LocalStr = NULL;
+
+ if (FfsName == NULL || InfFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (strlen(FfsName) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ LocalStr = (CHAR8 *) malloc (_MAX_PATH);
+
+ if (LocalStr == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (LocalStr, '\0', _MAX_PATH);
+
+ if (FirstIn) {
+ sprintf (LocalStr, "[files] \nEFI_FILE_NAME = %s \n", FfsName);
+ } else {
+ sprintf (LocalStr, "EFI_FILE_NAME = %s \n", FfsName);
+ }
+
+ if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+ printf ("Error while write data to %p file. \n", (void*)InfFile);
+ free (LocalStr);
+ return EFI_ABORTED;
+ }
+
+ free (LocalStr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Convert EFI file to PE or TE section
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] Type PE or TE and UI/Version
+ @param[in] OutputFilePath .te or .pe file
+ @param[in] UiString String for generate UI section usage, this parameter is optional
+ unless Type is EFI_SECTION_USER_INTERFACE.
+ @param[in] VerString String for generate Version section usage, this parameter is optional
+ unless Type is EFI_SECTION_VERSION.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibCreateFfsSection (
+ IN CHAR8* InputFilePath, OPTIONAL
+ IN CHAR8* Sections, OPTIONAL
+ IN UINT8 Type,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* UiString, OPTIONAL
+ IN CHAR8* VerString, OPTIONAL
+ IN CHAR8* GuidToolGuid, OPTIONAL
+ IN CHAR8* CompressType OPTIONAL
+ )
+{
+ CHAR8* SystemCommand;
+ SystemCommand = NULL;
+
+ //
+ // Call GenSec tool to generate FFS section.
+ //
+
+ //
+ // -s SectionType.
+ //
+ if (Type != 0) {
+ switch (Type) {
+ //
+ // Process compression section
+ //
+ case EFI_SECTION_COMPRESSION:
+ SystemCommand = malloc (
+ strlen (GENSEC_COMPRESSION) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (CompressType) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_COMPRESSION,
+ mSectionTypeName[Type],
+ CompressType,
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ //
+ // Process GUID defined section
+ //
+ case EFI_SECTION_GUID_DEFINED:
+ SystemCommand = malloc (
+ strlen (GENSEC_GUID) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (GuidToolGuid) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_GUID,
+ mSectionTypeName[Type],
+ GuidToolGuid,
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+ SystemCommand = malloc (
+ strlen (GENSEC_STR) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_STR,
+ mSectionTypeName[Type],
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ case EFI_SECTION_RAW:
+ SystemCommand = malloc (
+ strlen (GENSEC_STR) +
+ strlen (mSectionTypeName[Type]) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_STR,
+ mSectionTypeName[Type],
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ break;
+
+ default:
+ printf ("Please specify the section type while call GenSec tool.\n");
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ //
+ // Create Dummy section.
+ //
+ SystemCommand = malloc (
+ strlen (GENSEC_ALIGN) +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_ALIGN,
+ InputFilePath,
+ OutputFilePath
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Encapsulate FFSs to FV
+
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] BlockSize BlockSize is one HEX or DEC format value required by FV image.
+ @param[in] FileTakeSize
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapsulateFfsToFv (
+ IN CHAR8* InfFilePath,
+ IN CHAR8* InputFFSs,
+ IN CHAR8* OutputFilePath,
+ IN CHAR8* FvGuidName
+ )
+{
+
+ CHAR8* SystemCommand;
+ CHAR8* FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3";
+
+ SystemCommand = NULL;
+
+ if (OutputFilePath == NULL ||
+ InfFilePath == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InfFilePath != NULL) {
+ if (FvGuidName == NULL) {
+ SystemCommand = malloc (
+ strlen (GENFV_STR) +
+ strlen (InfFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ GENFV_STR,
+ InfFilePath, // -i
+ OutputFilePath // -o
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ } else {
+ //
+ // Have FvGuidName in it.
+ //
+ SystemCommand = malloc (
+ strlen (GENFV_FVGUID) +
+ strlen (InfFilePath) +
+ strlen (OutputFilePath) +
+ strlen (FvGuidName) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ GENFV_FVGUID,
+ InfFilePath, // -i
+ OutputFilePath, // -o
+ FvGuidName // FvNameGuid
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ }
+ }
+
+ if (InputFFSs != NULL) {
+ SystemCommand = malloc (
+ strlen (GENFV_FFS) +
+ strlen (InputFFSs) +
+ strlen (FfsGuid) +
+ strlen (OutputFilePath) +
+ 100
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ GENFV_FFS,
+ InputFFSs, // -f
+ FfsGuid, // -g
+ OutputFilePath // -o
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Convert a GUID to a string.
+
+
+ @param[in] Guid - Pointer to GUID to print.
+
+
+ @return The string after convert.
+
+**/
+CHAR8 *
+LibBfmGuidToStr (
+ IN EFI_GUID *Guid
+)
+{
+ CHAR8 * Buffer;
+
+ Buffer = NULL;
+
+ if (Guid == NULL) {
+ printf ("The guid is NULL while convert guid to string! \n");
+ return NULL;
+ }
+
+ Buffer = (CHAR8 *) malloc (36 + 1);
+
+ if (Buffer == NULL) {
+ printf ("Error while allocate resource! \n");
+ return NULL;
+ }
+ memset (Buffer, '\0', 36 + 1);
+
+ sprintf (
+ Buffer,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ Guid->Data1,
+ Guid->Data2,
+ Guid->Data3,
+ Guid->Data4[0],
+ Guid->Data4[1],
+ Guid->Data4[2],
+ Guid->Data4[3],
+ Guid->Data4[4],
+ Guid->Data4[5],
+ Guid->Data4[6],
+ Guid->Data4[7]
+ );
+
+ return Buffer;
+}
+
+/**
+ Encapsulate an FFS section file to an FFS file.
+
+ @param[in] Type Type is one FV file type defined in PI spec, which is one type of EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,
+ EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,
+ EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION, EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE. This option is required.
+ @param[in] InputFilePath Section file will be read into this FFS file. This option is required.
+ @param[in] OutputFilePath The created PI firmware file name. This option is required.
+ @param[in] FileGuid FileGuid is the unique identifier for this FFS file. This option is required.
+ @param[in] Fixed Set fixed attribute in FFS file header to indicate that the file may not be moved from its present location.
+ @param[in] SectionAlign FileAlign specifies FFS file alignment, which only support the following alignment: 8,16,128,512,1K,4K,32K,64K.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibEncapSectionFileToFFS (
+ IN UINT8 Type,
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath,
+ IN EFI_GUID FileGuid,
+ IN BOOLEAN Fixed,
+ IN UINT32 SectionAlign
+ )
+{
+ CHAR8* SystemCommand;
+ CHAR8* GuidStr;
+
+ SystemCommand = NULL;
+ GuidStr = NULL;
+
+ GuidStr = LibBfmGuidToStr(&FileGuid);
+
+ if (NULL == GuidStr) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Type == EFI_FV_FILETYPE_RAW) {
+ SystemCommand = malloc (
+ strlen (GENFFS_STR) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENFFS_STR,
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ } else {
+ //
+ // -t Type
+ // -i InputFilePath
+ // -o OutPutFilePath
+ // -g FileGuid
+ // -x Fixed
+ // -n SectionAlign
+ //
+ if (Fixed) {
+ SystemCommand = malloc (
+ strlen (GENFFS_FIX) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENFFS_FIX,
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ } else {
+ SystemCommand = malloc (
+ strlen (GENFFS_STR) +
+ strlen (mFfsFileType[Type]) +
+ strlen (InputFilePath) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENFFS_STR,
+ mFfsFileType[Type], // -t
+ InputFilePath, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ free (GuidStr);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+ }
+ }
+ free (GuidStr);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibCreateNewFdCopy(
+ IN CHAR8* OldFd,
+ IN CHAR8* NewFd
+)
+{
+ CHAR8* SystemCommand;
+ SystemCommand = NULL;
+
+
+ if (OldFd == NULL ||
+ NewFd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a copy the new file.
+ //
+
+ SystemCommand = malloc (
+ strlen (COPY_STR) +
+ strlen (OldFd) +
+ strlen (NewFd) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ COPY_STR,
+ OldFd,
+ NewFd
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will assemble the filename, directory and extend and return the combined string.
+ Like FileName = file1, Dir = c:\temp extend = txt, the output string will be:
+ c:\temp\file1.txt.
+
+ @param[in]
+ @param[in]
+ @param[in]
+
+ @retrun A string contain all the input information.
+
+**/
+CHAR8 *
+LibFilenameStrExtended (
+ IN CHAR8 *FileName,
+ IN CHAR8 *Dir,
+ IN CHAR8 *Extend
+)
+{
+ CHAR8 *RetStr;
+
+ RetStr = NULL;
+
+ if (FileName == NULL) {
+ return NULL;
+ }
+
+ if (Dir == NULL || Extend == NULL) {
+ return FileName;
+ }
+
+ RetStr = (CHAR8 *) malloc (strlen (FileName) +
+ strlen (Dir) +
+ strlen (Extend) +
+ strlen ("%s%s.%s") +
+ 1);
+ if (NULL == RetStr) {
+ return NULL;
+ }
+
+ memset (RetStr, '\0', (strlen (FileName) + strlen (Dir) + strlen (Extend) + strlen("%s%s.%s") + 1));
+
+ sprintf (RetStr, "%s%s.%s", Dir, FileName, Extend);
+
+ return RetStr;
+}
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+)
+{
+ CHAR8* SystemCommand;
+ SystemCommand = NULL;
+
+
+ if (DirName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (access (DirName, 0) == -1){
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Delete a directory and files in it
+ //
+ SystemCommand = malloc (
+ strlen (RMDIR_STR) +
+ strlen (DirName) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ RMDIR_STR,
+ DirName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a file.
+
+ @param[in] FileName Name of the file need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibBfmDeleteFile(
+ IN CHAR8 *FileName
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+
+ if (FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ //
+ // Delete a file.
+ //
+ SystemCommand = malloc (
+ strlen (DEL_STR) +
+ strlen (FileName) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ DEL_STR,
+ FileName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ free(SystemCommand);
+ return EFI_ABORTED;
+ }
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibBfmFreeFd (
+ FIRMWARE_DEVICE *Fd
+ )
+{
+ FV_INFORMATION *CurrentFv;
+ FV_INFORMATION *TempFv;
+ ENCAP_INFO_DATA *EncapData1;
+ ENCAP_INFO_DATA *EncapData2;
+
+ CurrentFv = NULL;
+ TempFv = NULL;
+ EncapData1 = NULL;
+ EncapData2 = NULL;
+
+ if (Fd == NULL) {
+ return;
+ }
+
+ CurrentFv = Fd->Fv;
+
+ do {
+ TempFv = CurrentFv;
+ CurrentFv = CurrentFv->FvNext;
+
+ if (TempFv->FvHeader != NULL) {
+ free (TempFv->FvHeader);
+ }
+ if (TempFv->FvExtHeader != NULL) {
+ free (TempFv->FvExtHeader);
+ }
+
+ //
+ // Free encapsulate data;
+ //
+ EncapData1 = TempFv->EncapData;
+
+ while (EncapData1 != NULL) {
+
+ EncapData2 = EncapData1;
+ EncapData1 = EncapData1->NextNode;
+
+ if (EncapData2->Data != NULL) {
+ free (EncapData2->Data);
+ }
+ if (EncapData2->FvExtHeader != NULL) {
+ free(EncapData2->FvExtHeader);
+ }
+ free (EncapData2);
+ EncapData2 = NULL;
+ }
+
+ EncapData1 = NULL;
+
+ free (TempFv);
+ TempFv = NULL;
+
+ } while (CurrentFv != NULL);
+
+ CurrentFv = NULL;
+ free (Fd);
+ Fd = NULL;
+
+ return;
+}
+
+/**
+ Generate the compressed section with specific type.
+ Type could be EFI_STANDARD_COMPRESSION or EFI_NOT_COMPRESSED
+
+ @param[in] InputFileName File name of the raw data.
+ @param[in] OutPutFileName File name of the sectioned data.
+ @param[in] CompressionType The compression type.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_ABORTED
+ @return EFI_OUT_OF_RESOURCES
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+LibGenCompressedSection (
+ CHAR8 *InputFileName,
+ CHAR8 *OutPutFileName,
+ UINT8 CompressionType
+)
+{
+ FILE *UnCompressFile;
+ FILE *CompressedFile;
+ VOID *UnCompressedBuffer;
+ VOID *CompressedBuffer;
+ UINT32 UnCompressedSize;
+ UINT32 CompressedSize;
+ CHAR8 *TempName;
+ CHAR8 *TemDir;
+ CHAR8 *TemString;
+ EFI_STATUS Status;
+
+ UnCompressFile = NULL;
+ CompressedFile = NULL;
+ UnCompressedBuffer = NULL;
+ CompressedBuffer = NULL;
+ TempName = NULL;
+ TemDir = NULL;
+ TemString = NULL;
+ UnCompressedSize = 0;
+ CompressedSize = 0;
+
+ if ( InputFileName == NULL ||
+ OutPutFileName == NULL) {
+ printf ("Error while generate compressed section!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ UnCompressFile = fopen (InputFileName, "rb");
+ if (UnCompressFile == NULL) {
+ printf ("Error while open file %s \n", InputFileName);
+ return EFI_ABORTED;
+ }
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ fclose (UnCompressFile);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ TemString = GenTempFile ();
+ TempName= LibFilenameStrExtended (strrchr(TemString, OS_SEP), TemDir, "comp");
+ free (TemString);
+ TemString = NULL;
+ if (TempName == NULL) {
+ fclose(UnCompressFile);
+ return EFI_ABORTED;
+ }
+
+ CompressedFile = fopen (TempName, "wb+");
+ if (CompressedFile == NULL) {
+ printf ("Error while open file %s \n", TempName);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+ //
+ // Get the original file size;
+ //
+ fseek(UnCompressFile,0,SEEK_SET);
+ fseek(UnCompressFile,0,SEEK_END);
+
+ UnCompressedSize = ftell(UnCompressFile);
+
+ fseek(UnCompressFile,0,SEEK_SET);
+
+ UnCompressedBuffer = malloc (UnCompressedSize);
+
+ if (UnCompressedBuffer == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CompressedBuffer = malloc (UnCompressedSize);
+
+ if (CompressedBuffer == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ free (UnCompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (fread (UnCompressedBuffer, 1, (size_t) UnCompressedSize, UnCompressFile) == (size_t) UnCompressedSize) {
+ CompressedSize = UnCompressedSize;
+
+ Status = EfiCompress ( UnCompressedBuffer,
+ UnCompressedSize,
+ CompressedBuffer,
+ &CompressedSize);
+
+ if (EFI_ERROR(Status)) {
+ printf("Error while do compress operation! \n");
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+
+ if (CompressedSize > UnCompressedSize) {
+ printf("Error while do compress operation! \n");
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error while reading file %s! \n", InputFileName);
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose (CompressedFile);
+ fclose(UnCompressFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Write the compressed data into output file
+ //
+ if (fwrite (CompressedBuffer, 1, (size_t) CompressedSize, CompressedFile) != (size_t) CompressedSize) {
+ printf ("Error while writing %s file. \n", OutPutFileName);
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ free (TempName);
+ return EFI_ABORTED;
+ }
+
+ fclose(UnCompressFile);
+ fclose (CompressedFile);
+ free (UnCompressedBuffer);
+ free (CompressedBuffer);
+
+ //
+ // Call GenSec tool to generate the compressed section.
+ //
+ LibCreateFfsSection(TempName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, "PI_STD");
+ free (TempName);
+ TempName = NULL;
+
+ } else if (CompressionType == EFI_NOT_COMPRESSED) {
+
+ LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, "PI_NONE");
+
+ } else {
+ printf ("Error while generate compressed section, unknown compression type! \n");
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+)
+{
+ EFI_GUID Guid;
+ STRING_LIST *Tool;
+ GUID_SEC_TOOL_ENTRY *FirstGuidTool;
+ GUID_SEC_TOOL_ENTRY *LastGuidTool;
+ GUID_SEC_TOOL_ENTRY *NewGuidTool;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
+ "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
+ "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
+ "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
+ "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
+ };
+
+
+ Tool = NULL;
+ FirstGuidTool = NULL;
+ LastGuidTool = NULL;
+ NewGuidTool = NULL;
+ Index = 0;
+
+ for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
+ Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
+ if ((Tool != NULL) &&
+ (Tool->Count == 3)
+ ) {
+ Status = StringToGuid (Tool->Strings[0], &Guid);
+ if (!EFI_ERROR (Status)) {
+ NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
+ if (NewGuidTool != NULL) {
+ memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
+ NewGuidTool->Name = CloneString(Tool->Strings[1]);
+ NewGuidTool->Path = CloneString(Tool->Strings[2]);
+ NewGuidTool->Next = NULL;
+ } else {
+ printf ( "Fail to allocate memory. \n");
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ }
+ return NULL;
+ }
+ if (FirstGuidTool == NULL) {
+ FirstGuidTool = NewGuidTool;
+ } else {
+ LastGuidTool->Next = NewGuidTool;
+ }
+ LastGuidTool = NewGuidTool;
+ }
+ } else {
+ fprintf (stdout, "Error");
+ }
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ Tool = NULL;
+ }
+ }
+ return FirstGuidTool;
+}
+
+EFI_STATUS
+LibLocateFvViaFvId (
+ IN FIRMWARE_DEVICE *FdData,
+ IN CHAR8 *FvId,
+ IN OUT FV_INFORMATION **FvInFd
+)
+{
+ UINT8 FvIndex1;
+ UINT8 FvIndex2;
+ BOOLEAN FvFoundFlag;
+
+ FvIndex1 = 0;
+ FvIndex2 = 0;
+ FvFoundFlag = FALSE;
+
+ if (FdData == NULL || FvId == NULL) {
+ printf ( "Error while find FV in FD. \n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FvInFd = FdData->Fv;
+
+ FvIndex1 = (UINT8) atoi (FvId + 2);
+
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvName) != NULL) {
+ FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+ if ((FvIndex2 <= FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 >= FvIndex1)) {
+ FvFoundFlag = TRUE;
+ break;
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ }
+
+ //
+ // The specified FV id has issue, can not find the FV in FD.
+ //
+ if (!FvFoundFlag) {
+ printf ( "Error while find FV in FD. \n");
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+EFI_STATUS
+LibPatchResetVectorAndFitTableData (
+IN CHAR8 *OutputFileName,
+IN PATCH_DATA_PAD_FFS *PatchData
+)
+{
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ UINT8 *Buffer;
+ UINT32 Count;
+
+
+ Count = 0;
+ Buffer = NULL;
+ NewFvFile = NULL;
+
+ if (OutputFileName == NULL || PatchData == NULL) {
+ return EFI_ABORTED;
+ }
+
+ NewFvFile = fopen (OutputFileName, "rb+");
+ if (NewFvFile == NULL) {
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile, 0, SEEK_SET);
+ fseek(NewFvFile, 0, SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+
+ do {
+
+ //
+ // The FV length should larger than Offset.
+ //
+ if (NewFvLength < PatchData->Offset) {
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,PatchData->Offset,SEEK_SET);
+
+ Buffer = (UINT8 *) malloc (PatchData->Length);
+
+ if (Buffer == NULL) {
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) PatchData->Length, NewFvFile) != (size_t) PatchData->Length) {
+ fclose (NewFvFile);
+ free(Buffer);
+ return EFI_ABORTED;
+ }
+
+ //
+ // The area used to patch data should be filled by 0xff.
+ //
+ for (Count = 0; Count< PatchData->Length; Count++) {
+ if (Buffer[Count] != 0xff){
+ fclose (NewFvFile);
+ free(Buffer);
+ return EFI_ABORTED;
+ }
+ }
+
+ free(Buffer);
+
+ fseek(NewFvFile,PatchData->Offset,SEEK_SET);
+
+ if (fwrite (PatchData->Data, 1, (size_t) PatchData->Length, NewFvFile) != (size_t) PatchData->Length) {
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ PatchData = PatchData->NextNode;
+ } while (PatchData != NULL);
+
+ fclose (NewFvFile);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ OUT CHAR8 **OutputFile
+)
+{
+ EFI_STATUS Status;
+ UINT32 ParentType;
+ UINT8 ParentLevel;
+ UINT32 Type;
+ UINT8 Level;
+ CHAR8 *InfFileName;
+ FILE *InfFile;
+ ENCAP_INFO_DATA *LocalEncapData;
+ BOOLEAN FfsFoundFlag;
+ UINT32 Index;
+ CHAR8 *ExtractionTool;
+ BOOLEAN IsLastLevelFfs;
+ BOOLEAN IsLeafFlagIgnore;
+ BOOLEAN FirstInFlag;
+ CHAR8 *InputFileName;
+ CHAR8 *OutputFileName;
+ CHAR8 *FvGuidName;
+
+ Index = 0;
+ ParentType = 0;
+ ParentLevel = 0;
+ Type = 0;
+ Level = 0;
+ FfsFoundFlag = FALSE;
+ ExtractionTool = NULL;
+ InputFileName = NULL;
+ OutputFileName = NULL;
+ IsLastLevelFfs = TRUE;
+ IsLeafFlagIgnore = FALSE;
+ FirstInFlag = TRUE;
+ FvGuidName = NULL;
+
+ //
+ // Encapsulate from the lowest FFS file level.
+ //
+ LocalEncapData = FvInFd->EncapData;
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+
+ //
+ // Get FV Name GUID
+ //
+
+ while (LocalEncapData != NULL) {
+ //
+ // Has changed.
+ //
+ if (LocalEncapData->Level > Level) {
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_FFS) {
+ ParentLevel = Level;
+ ParentType = Type;
+ }
+
+ Level = LocalEncapData->Level;
+ Type = LocalEncapData->Type;
+ }
+
+ if (LocalEncapData->NextNode != NULL) {
+ LocalEncapData = LocalEncapData->NextNode;
+ } else {
+ break;
+ }
+ }
+
+ do {
+ switch (ParentType) {
+ case BFM_ENCAP_TREE_FV:
+
+ //
+ // Generate FV.inf attributes.
+ //
+ InfFileName = LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "inf");
+
+ InfFile = fopen (InfFileName, "wt+");
+
+ if (InfFile == NULL) {
+ printf ("Could not open inf file %s to store FV information. \n", InfFileName);
+ return EFI_ABORTED;
+ }
+
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) {
+ //
+ // FV GUID Name memory allocation
+ //
+ FvGuidName = (CHAR8 *) malloc (255);
+
+ if (FvGuidName == NULL) {
+ printf ("Out of resource, memory allocation failed. \n");
+ fclose (InfFile);
+ return EFI_ABORTED;
+ }
+
+ memset(FvGuidName, '\0', 255);
+
+ sprintf(
+ FvGuidName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+ LocalEncapData->FvExtHeader->FvName.Data1,
+ LocalEncapData->FvExtHeader->FvName.Data2,
+ LocalEncapData->FvExtHeader->FvName.Data3,
+ LocalEncapData->FvExtHeader->FvName.Data4[0],
+ LocalEncapData->FvExtHeader->FvName.Data4[1],
+ LocalEncapData->FvExtHeader->FvName.Data4[2],
+ LocalEncapData->FvExtHeader->FvName.Data4[3],
+ LocalEncapData->FvExtHeader->FvName.Data4[4],
+ LocalEncapData->FvExtHeader->FvName.Data4[5],
+ LocalEncapData->FvExtHeader->FvName.Data4[6],
+ LocalEncapData->FvExtHeader->FvName.Data4[7]
+ );
+
+ } else {
+ FvGuidName = NULL;
+ }
+
+
+ if (ParentLevel == 1) {
+ Status = LibFvHeaderOptionToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->BlockMap, InfFile, TRUE);
+ } else {
+ Status = LibFvHeaderOptionToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->BlockMap, InfFile, FALSE);
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ printf ("Generate FV INF file [Options] section failed.\n");
+ fclose (InfFile);
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ return Status;
+ }
+
+ Status = LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->Attributes, InfFile);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Generate FV header attribute failed.\n");
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ fclose (InfFile);
+ return Status;
+ }
+ if (LocalEncapData->FvExtHeader != NULL) {
+ Status = LibGenExtFile(LocalEncapData->FvExtHeader, InfFile);
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ if (EFI_ERROR(Status)) {
+ printf("Generate FV EXT header failed.\n");
+ fclose (InfFile);
+ return Status;
+ }
+ FvGuidName = NULL;
+ }
+
+ //
+ // Found FFSs from Fv structure.
+ //
+ FfsFoundFlag = FALSE;
+ for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+
+ //
+ // For the last level FFS, the level below FFSs we should not care the IsLeaf Flag.
+ //
+ if (IsLastLevelFfs) {
+ IsLeafFlagIgnore = TRUE;
+ } else {
+ IsLeafFlagIgnore = FvInFd->FfsAttuibutes[Index].IsLeaf;
+ }
+
+ if (FvInFd->FfsAttuibutes[Index].Level >= ParentLevel + 1 && IsLeafFlagIgnore) {
+ if (FirstInFlag) {
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, TRUE);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section. \n");
+ fclose (InfFile);
+ return Status;
+ }
+
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ FirstInFlag = FALSE;
+ } else {
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section. \n");
+ fclose (InfFile);
+ return Status;
+ }
+
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ }
+ FfsFoundFlag = TRUE;
+ }
+ //
+ // Also add the sub FV
+ //
+ if (FvInFd->FfsAttuibutes[Index].Level - 1 == ParentLevel+ 1) {
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel + 2) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_GUIDED_SECTION) {
+ Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section.\n");
+ fclose (InfFile);
+ return Status;
+ }
+
+ FvInFd->FfsAttuibutes[Index].Level = 0;
+ }
+
+ }
+ }
+
+ IsLastLevelFfs = FALSE;
+ FirstInFlag = TRUE;
+ if (!FfsFoundFlag) {
+ Status = LibAddFfsFileToFvInf (OutputFileName, InfFile, TRUE);
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV inf file [files] section.\n");
+ fclose (InfFile);
+ return Status;
+ }
+ }
+ /*
+ if (OutputFileName != NULL && FfsFoundFlag) {
+ Status = LibAddFfsFileToFvInf (OutputFileName, InfFile, FALSE);
+
+ if (EFI_ERROR (Status)) {
+ //Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+ return Status;
+ }
+ }
+ */
+ //
+ // Create FV
+ //
+ fclose (InfFile);
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "FV");
+ Status = LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileName, FvGuidName);
+ if (FvGuidName != NULL) {
+ free (FvGuidName);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Patch FIT Table Data or reset vector data if exist.
+ //
+ if ((FvInFd->PatchData != NULL) && (1 == ParentLevel)) {
+ Status = LibPatchResetVectorAndFitTableData(OutputFileName, FvInFd->PatchData);
+ if (EFI_ERROR (Status)) {
+ printf ("Error while patch FIT Table Data or reset vector data. \n");
+ return Status;
+ }
+ }
+
+ break;
+ case BFM_ENCAP_TREE_FFS:
+ if (OutputFileName != NULL) {
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "ffs");
+
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == Level) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, ((EFI_FFS_FILE_HEADER *)LocalEncapData->Data)->Name, FALSE, 0);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FFS file. \n");
+ return Status;
+ }
+ }
+ break;
+ case BFM_ENCAP_TREE_GUIDED_SECTION:
+ //
+ // Create the guided section original data, do compress operation.
+ //
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "compressed");
+
+ //
+ // Use the guided section header guid to find out compress application name.
+ //
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ ExtractionTool =
+ LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ (EFI_GUID *)LocalEncapData->Data
+ );
+
+ Status = LibCreateGuidedSectionOriginalData (InputFileName, ExtractionTool, OutputFileName);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while compress guided data. \n");
+ return Status;
+ }
+
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "guided");
+
+ Status = LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_GUID_DEFINED, OutputFileName, NULL, NULL, LibBfmGuidToStr((EFI_GUID *)LocalEncapData->Data), NULL);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate guided section. \n");
+ return Status;
+ }
+
+ break;
+ case BFM_ENCAP_TREE_COMPRESS_SECTION:
+ if (OutputFileName != NULL) {
+ InputFileName = OutputFileName;
+
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "comsec");
+
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+
+ Status = LibGenCompressedSection (InputFileName, OutputFileName, *(UINT8 *)(LocalEncapData->Data));
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate compressed section. \n");
+ return Status;
+ }
+ }
+ break;
+ case BFM_ENCAP_TREE_FV_SECTION:
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ Status = LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV section. \n");
+ return Status;
+ }
+
+ InputFileName = OutputFileName;
+ OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+ //
+ // Make it alignment.
+ //
+ Status = LibCreateFfsSection(InputFileName, NULL, 0, OutputFileName, NULL, NULL, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while generate FV section. \n");
+ return Status;
+ }
+
+ break;
+ default:
+ printf("Don't know how to encapsulate the FD file! \n");
+ return EFI_ABORTED;
+ }
+
+
+ //
+ // Find next level and encapsulate type
+ //
+ ParentLevel -= 1;
+ LocalEncapData = FvInFd->EncapData;
+ while (LocalEncapData->NextNode != NULL) {
+ if (LocalEncapData->Level == ParentLevel) {
+ ParentType = LocalEncapData->Type;
+ break;
+ }
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ } while (ParentLevel != 0);
+
+
+ *OutputFile = OutputFileName;
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+LibLocateBfv(
+ IN FIRMWARE_DEVICE *FdData,
+ IN OUT CHAR8 **FvId,
+ IN OUT FV_INFORMATION **FvInFd
+)
+{
+ UINT8 FvIndex1;
+ UINT8 FvIndex2;
+ BOOLEAN FvFoundFlag;
+
+ FvIndex1 = 0;
+ FvIndex2 = 0;
+ FvFoundFlag = FALSE;
+
+ if (FdData == NULL || FvId == NULL || FvInFd == NULL) {
+ return EFI_ABORTED;
+ }
+
+ *FvId = (*FvInFd)->FvName;
+
+ FvIndex1 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+ *FvInFd = FdData->Fv;
+
+ while (FvInFd != NULL) {
+ if (((*FvInFd)->FvName) != NULL) {
+ FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+ if ((FvIndex2 <= FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 >= FvIndex1)) {
+ FvFoundFlag = TRUE;
+ break;
+ }
+ if ((*FvInFd)->FvNext == 0) {
+ break;
+ }
+ *FvInFd = (*FvInFd)->FvNext;
+ }
+ }
+
+ //
+ // The specified FV id has issue, can not find the FV in FD.
+ //
+ if (!FvFoundFlag) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get the length of a file.
+
+ @param[in] FileName The name of a file.
+
+ @retval The length of file.
+
+**/
+UINT64
+GetFileSize (
+ IN CHAR8 *FileName
+)
+{
+ FILE* File;
+ UINT64 Length;
+
+ File = NULL;
+
+ if (FileName == NULL) {
+ return 0;
+ }
+ File = fopen(FileName, "r");
+
+ if (File == NULL) {
+ return 0;
+ }
+ fseek(File, 0L, SEEK_END);
+ Length = ftell(File);
+ fclose(File);
+
+ return Length;
+}
+
+/**
+
+ Get the length of BFV PAD file.
+
+ @retval The length of PAD file.
+
+**/
+UINT32
+GetBfvPadSize (
+ VOID
+)
+{
+ return PadSizeOfBfv;
+}
+
diff --git a/Platform/Intel/Tools/BfmLib/BinFileManager.c b/Platform/Intel/Tools/BfmLib/BinFileManager.c
new file mode 100644
index 0000000000..8c8b67bd37
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/BinFileManager.c
@@ -0,0 +1,1024 @@
+/** @file
+
+ The main entry of BFM tool.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinFileManager.h"
+
+BOOLEAN mFvGuidIsSet = FALSE;
+EFI_GUID mFvNameGuid = {0};
+CHAR8* mFvNameGuidString = NULL;
+CHAR8* mGuidToolDefinition = "GuidToolDefinitionConf.ini";
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+
+
+/**
+ Search the config file from the path list.
+
+ Split the path from env PATH, and then search the cofig
+ file from these paths. The priority is from left to
+ right of PATH string. When met the first Config file, it
+ will break and return the pointer to the full file name.
+
+ @param PathList the pointer to the path list.
+ @param FileName the pointer to the file name.
+
+ @retval The pointer to the file name.
+ @return NULL An error occurred.
+**/
+CHAR8 *
+SearchConfigFromPathList (
+ IN CHAR8 *PathList,
+ IN CHAR8 *FileName
+)
+{
+ CHAR8 *CurDir;
+ CHAR8 *FileNamePath;
+
+ CurDir = NULL;
+ FileNamePath = NULL;
+#ifndef __GNUC__
+ CurDir = strtok (PathList,";");
+#else
+ CurDir = strtok (PathList,":");
+#endif
+ while (CurDir != NULL) {
+ FileNamePath = (char *)calloc(
+ strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
+ sizeof(char)
+ );
+ if (FileNamePath == NULL) {
+ return NULL;
+ }
+ sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
+ if (access (FileNamePath, 0) != -1) {
+ return FileNamePath;
+ }
+#ifndef __GNUC__
+ CurDir = strtok(NULL, ";");
+#else
+ CurDir = strtok(NULL, ":");
+#endif
+ free (FileNamePath);
+ FileNamePath = NULL;
+ }
+ return NULL;
+}
+
+/**
+
+ Show the FD image layout information. Only display the modules with UI name.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] FvName The FV ID in the FD file;
+ @param[in] ViewFlag Is this call for view or other operate(add/del/replace)
+ @param[in] FdData The Fd data structure store the FD information.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageView (
+ IN CHAR8* FdInName,
+ IN CHAR8* FvName,
+ IN BOOLEAN ViewFlag,
+ IN FIRMWARE_DEVICE **FdData
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *LocalFdData;
+ FV_INFORMATION *CurrentFv;
+ FILE *InputFile;
+ UINT32 FvSize;
+ UINTN BytesRead;
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage;
+ UINT32 FfsCount;
+ UINT8 FvCount;
+ UINT8 LastFvNumber;
+
+ LocalFdData = NULL;
+ CurrentFv = NULL;
+ FvImage = NULL;
+ FvSize = 0;
+ BytesRead = 0;
+ FfsCount = 0;
+ FvCount = 0;
+ LastFvNumber = 0;
+
+ //
+ // Check the FD file name/path.
+ //
+ if (FdInName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Open the file containing the FV
+ //
+ InputFile = fopen (FdInName, "rb");
+ if (InputFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = LibFindFvInFd (InputFile, &LocalFdData);
+
+ if (EFI_ERROR(Status)) {
+ fclose (InputFile);
+ return EFI_ABORTED;
+ }
+
+ CurrentFv = LocalFdData->Fv;
+
+ do {
+
+ memset (CurrentFv->FvName, '\0', _MAX_PATH);
+
+ if (LastFvNumber == 0) {
+ sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
+ } else {
+ sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
+ }
+
+ //
+ // Determine size of FV
+ //
+ if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return EFI_ABORTED;
+ }
+
+ Status = LibGetFvSize(InputFile, &FvSize);
+ if (EFI_ERROR (Status)) {
+ fclose (InputFile);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET);
+
+ FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize);
+
+ if (FvImage == NULL) {
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return EFI_ABORTED;
+ }
+
+ BytesRead = fread (FvImage, 1, FvSize, InputFile);
+ if ((unsigned int) BytesRead != FvSize) {
+ free (FvImage);
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Collect FV information each by each.
+ //
+ Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &FfsCount, ViewFlag, FALSE);
+ free (FvImage);
+ FvImage = NULL;
+ if (EFI_ERROR (Status)) {
+ fclose (InputFile);
+ LibBfmFreeFd( LocalFdData);
+ return Status;
+ }
+ FvCount = CurrentFv->FvLevel;
+ LastFvNumber = LastFvNumber+FvCount;
+
+ FfsCount = 0;
+
+ CurrentFv = CurrentFv->FvNext;
+
+ } while (CurrentFv != NULL);
+
+ if (!ViewFlag) {
+ *FdData = LocalFdData;
+ } else {
+ LibBfmFreeFd( LocalFdData);
+ }
+
+ fclose (InputFile);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add an FFS file into a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] NewFile The name of the file add in;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageAdd (
+ IN CHAR8* FdInName,
+ IN CHAR8* NewFile,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ UINT64 NewFfsLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ UINT8 FvEncapLevel;
+ UINT8 NewAddedFfsLevel;
+ BOOLEAN FfsLevelFoundFlag;
+ CHAR8 *OutputFileName;
+ CHAR8 *FvId;
+ BOOLEAN FirstInFlag;
+ BOOLEAN FvGuidExisted;
+
+ NewFvLength = 0;
+ FvEncapLevel = 0;
+ NewAddedFfsLevel = 0;
+
+ FfsLevelFoundFlag = FALSE;
+ FirstInFlag = TRUE;
+ FdData = NULL;
+ FvInFd = NULL;
+ LocalEncapData = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ LocalEncapDataTemp = NULL;
+ OutputFileName = NULL;
+ FvId = NULL;
+ FvGuidExisted = FALSE;
+
+ //
+ // Get the size of ffs file to be inserted.
+ //
+ NewFfsLength = GetFileSize(NewFile);
+
+ Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while parse %s FD image.\n", FdInName);
+ return Status;
+ }
+ //
+ // Check the FvGuid whether exists or not when the BIOS hasn't default setting.
+ // If the FV image with -g GUID can't be found, the storage is still saved into the BFV and report warning message.
+ //
+ FvInFd = FdData->Fv;
+ do {
+ if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+ FvGuidExisted = TRUE;
+ break;
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+ if (mFvGuidIsSet && !FvGuidExisted) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ //
+ // Iterate to write FFS to each BFV.
+ //
+ FvInFd = FdData->Fv;
+ do {
+ if ((FvGuidExisted && mFvGuidIsSet && FvInFd->IsInputFvFlag) || ((!FvGuidExisted || (!mFvGuidIsSet)) && FvInFd->IsBfvFlag)) {
+
+ Status = LibLocateBfv (FdData, &FvId, &FvInFd);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while locate BFV from FD.\n");
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ //
+ // Determine the new added ffs file level in the FV.
+ //
+ LocalEncapData = FvInFd->EncapData;
+
+ while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
+ if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
+ //
+ // Found the FFS level in this FV.
+ //
+ LocalEncapDataTemp = LocalEncapData;
+ while (LocalEncapDataTemp != NULL) {
+ if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
+ NewAddedFfsLevel = LocalEncapDataTemp->Level;
+ FfsLevelFoundFlag = TRUE;
+ break;
+ }
+ if (LocalEncapDataTemp->NextNode != NULL) {
+ LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+ } else {
+ break;
+ }
+ }
+ }
+ FvEncapLevel ++;
+ }
+
+ if (LocalEncapData->NextNode == NULL) {
+ break;
+ } else {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+
+ //
+ // Add the new file into FV.
+ //
+ FvInFd->FfsNumbers += 1;
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ printf ("The NewFile name is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName[_MAX_PATH - 1] = 0;
+ FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level = NewAddedFfsLevel;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n",(unsigned long) GetBfvPadSize (), (unsigned long long)NewFfsLength);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ if (FirstInFlag) {
+ //
+ // Write New Fv file into the NewFd file.
+ //
+ Status = LibCreateNewFdCopy (FdInName, FdOutName);
+ if (EFI_ERROR (Status)) {
+ printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+ FirstInFlag = FALSE;
+ }
+
+ NewFdFile = fopen (FdOutName, "rb+");
+ if (NewFdFile == NULL) {
+ printf("Error while create FD file %s. \n", FdOutName);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ NewFvFile = fopen (OutputFileName, "rb+");
+
+ if (NewFvFile == NULL) {
+ printf("Error while create Fv file %s. \n", OutputFileName);
+ fclose(NewFdFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+
+ fseek(NewFvFile,0,SEEK_SET);
+
+ Buffer = malloc ((size_t)NewFvLength);
+
+ if (Buffer == NULL) {
+ printf ("Error while allocate resource! \n");
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ printf("Error while reading Fv file %s. \n", OutputFileName);
+ free (Buffer);
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
+ printf("Error while writing FD file %s. \n", FdOutName);
+ fclose(NewFdFile);
+ fclose (NewFvFile);
+ free (Buffer);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
+ free (Buffer);
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ free (Buffer);
+ Buffer = NULL;
+
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+
+ LibBfmFreeFd(FdData);
+
+ if (TemDir == NULL) {
+ if (mFvGuidIsSet) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
+ } else {
+ printf ("BFV image can't be found.\n");
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ Status = LibRmDir (TemDir);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while remove temporary directory. \n");
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Replace an FFS file into a specify FV.
+
+ @param[in] FdInName Input FD binary/image file name;
+ @param[in] NewFile The name of the file add in;
+ @param[in] FdOutName Name of output fd file.
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageReplace (
+ IN CHAR8* FdInName,
+ IN CHAR8* NewFile,
+ IN CHAR8* FdOutName
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ FV_INFORMATION *FvInFd;
+ FILE* NewFdFile;
+ FILE* NewFvFile;
+ UINT64 NewFvLength;
+ UINT64 NewFfsLength;
+ VOID* Buffer;
+ CHAR8 *TemDir;
+ CHAR8 *OutputFileName;
+ CHAR8 *FvId;
+ BOOLEAN FirstInFlag;
+ UINT32 Index;
+ BOOLEAN FvToBeUpdate;
+ BOOLEAN FdIsUpdate;
+ ENCAP_INFO_DATA *LocalEncapData;
+ ENCAP_INFO_DATA *LocalEncapDataTemp;
+ UINT8 FvEncapLevel;
+ UINT8 NewAddedFfsLevel;
+ BOOLEAN FfsLevelFoundFlag;
+ EFI_GUID EfiNewAddToBfvGuid;
+ FILE* FfsFile;
+ UINTN BytesRead;
+ BOOLEAN ReplaceSameFv;
+ BOOLEAN FvGuidExisted;
+
+ NewFvLength = 0;
+ FdIsUpdate = FALSE;
+ FirstInFlag = TRUE;
+ FdData = NULL;
+ FvInFd = NULL;
+ NewFdFile = NULL;
+ NewFvFile = NULL;
+ Buffer = NULL;
+ TemDir = NULL;
+ OutputFileName = NULL;
+ FvId = NULL;
+ FfsFile = NULL;
+ BytesRead = 0;
+ ReplaceSameFv = FALSE;
+ FvGuidExisted = FALSE;
+
+ //
+ // Get the size of ffs file to be inserted.
+ //
+ NewFfsLength = GetFileSize(NewFile);
+ //
+ // Get FFS GUID
+ //
+ FfsFile = fopen (NewFile, "rb");
+ if (FfsFile == NULL) {
+ printf ("Error while read %s.\n", NewFile);
+ return EFI_ABORTED;
+ }
+ fseek (FfsFile, 0, SEEK_SET);
+ BytesRead = fread (&EfiNewAddToBfvGuid, 1, sizeof(EFI_GUID), FfsFile);
+ fclose (FfsFile);
+ if (BytesRead != sizeof(EFI_GUID)) {
+ printf ("Error while read the GUID from %s.\n", NewFile);
+ return EFI_ABORTED;
+ }
+ Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
+
+ if (EFI_ERROR (Status)) {
+ printf ("Error while parse %s FD image.\n", FdInName);
+ return Status;
+ }
+
+ //
+ // Check the FvGuid whether exists or not when the BIOS has default setting.
+ // 1. No option means the storage is saved into the same FV image.
+ // 2. The FV image with -g GUID can't be found. The storage is still saved into the same FV image and report warning message.
+ //
+ if (!mFvGuidIsSet) {
+ ReplaceSameFv = TRUE;
+ }
+ FvInFd = FdData->Fv;
+ do {
+ if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+ FvGuidExisted = TRUE;
+ break;
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+ if (mFvGuidIsSet && !FvGuidExisted) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
+ ReplaceSameFv = TRUE;
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ //
+ // Interate to insert or replace default setting to Fv
+ //
+ FvInFd = FdData->Fv;
+ do {
+ FvToBeUpdate = FALSE;
+ if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+ FvToBeUpdate = TRUE;
+ }
+
+ Status = LibLocateBfv (FdData, &FvId, &FvInFd);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while locate BFV from FD.\n");
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ Index = 0;
+ while (Index <= FvInFd->FfsNumbers) {
+ //
+ // Locate the multi-platform ffs in Fv and then replace or delete it.
+ //
+ if (!CompareGuid(&FvInFd->FfsHeader[Index].Name, &EfiNewAddToBfvGuid)) {
+ if (ReplaceSameFv) {
+ FvToBeUpdate = TRUE;
+ }
+ break;
+ }
+ Index ++;
+ }
+
+ if (FvToBeUpdate || (Index <= FvInFd->FfsNumbers)) {
+ if (FvToBeUpdate) {
+ FdIsUpdate = TRUE;
+ if (Index <= FvInFd->FfsNumbers) {
+ //
+ // Override original default data by New File
+ //
+ if (strlen (NewFile) > _MAX_PATH - 1) {
+ printf ("The NewFile name is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
+ FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
+ } else {
+ FfsLevelFoundFlag = FALSE;
+ FvEncapLevel = 0;
+ NewAddedFfsLevel = 0;
+ //
+ // Determine the new added ffs file level in the FV.
+ //
+ LocalEncapData = FvInFd->EncapData;
+
+ while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
+ if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
+ if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
+ //
+ // Found the FFS level in this FV.
+ //
+ LocalEncapDataTemp = LocalEncapData;
+ while (LocalEncapDataTemp != NULL) {
+ if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
+ NewAddedFfsLevel = LocalEncapDataTemp->Level;
+ FfsLevelFoundFlag = TRUE;
+ break;
+ }
+ if (LocalEncapDataTemp->NextNode != NULL) {
+ LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+ } else {
+ break;
+ }
+ }
+ }
+ FvEncapLevel ++;
+ }
+
+ if (LocalEncapData->NextNode == NULL) {
+ break;
+ } else {
+ LocalEncapData = LocalEncapData->NextNode;
+ }
+ }
+
+ //
+ // Add the new file into FV.
+ //
+ FvInFd->FfsNumbers += 1;
+ memcpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH);
+ FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level = NewAddedFfsLevel;
+ }
+ } else {
+ //
+ // Remove original default data from FV.
+ //
+ FvInFd->FfsAttuibutes[Index].FfsName[0] = '\0';
+ }
+
+ if (TemDir == NULL) {
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR)+ strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+
+ Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n", (unsigned long) GetBfvPadSize (), (unsigned long long) NewFfsLength);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+
+ if (FirstInFlag) {
+ //
+ // Write New Fv file into the NewFd file.
+ //
+ Status = LibCreateNewFdCopy (FdInName, FdOutName);
+ if (EFI_ERROR (Status)) {
+ printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
+ LibBfmFreeFd(FdData);
+ return Status;
+ }
+ FirstInFlag = FALSE;
+ }
+
+ NewFdFile = fopen (FdOutName, "rb+");
+ if (NewFdFile == NULL) {
+ printf("Error while create FD file %s. \n", FdOutName);
+ LibBfmFreeFd(FdData);
+ return EFI_ABORTED;
+ }
+
+ NewFvFile = fopen (OutputFileName, "rb+");
+
+ if (NewFvFile == NULL) {
+ printf("Error while create Fv file %s. \n", OutputFileName);
+ LibBfmFreeFd(FdData);
+ fclose (NewFdFile);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFvFile,0,SEEK_SET);
+ fseek(NewFvFile,0,SEEK_END);
+
+ NewFvLength = ftell(NewFvFile);
+
+ fseek(NewFvFile,0,SEEK_SET);
+
+ Buffer = malloc ((size_t)NewFvLength);
+
+ if (Buffer == NULL) {
+ LibBfmFreeFd(FdData);
+ fclose (NewFdFile);
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+ printf("Error while read Fv file %s. \n", OutputFileName);
+ LibBfmFreeFd(FdData);
+ free (Buffer);
+ fclose (NewFdFile);
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+ fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+
+ if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+ if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
+ printf("Error while write FD file %s. \n", FdOutName);
+ fclose(NewFdFile);
+ fclose (NewFvFile);
+ LibBfmFreeFd(FdData);
+ free (Buffer);
+ return EFI_ABORTED;
+ }
+ } else {
+ printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
+ free (Buffer);
+ LibBfmFreeFd(FdData);
+ fclose (NewFdFile);
+ fclose (NewFvFile);
+ return EFI_ABORTED;
+ }
+
+ fclose(NewFdFile);
+ fclose(NewFvFile);
+ free (Buffer);
+ Buffer = NULL;
+
+ }
+ FvInFd = FvInFd->FvNext;
+ } while (FvInFd != NULL);
+
+ LibBfmFreeFd(FdData);
+
+ if (TemDir == NULL || !FdIsUpdate) {
+ if (mFvGuidIsSet) {
+ printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
+ } else {
+ printf ("BFV image can't be found.\n");
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ Status = LibRmDir (TemDir);
+
+ if (EFI_ERROR (Status)) {
+ printf("Error while remove temporary directory. \n");
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ The main entry of BFM tool.
+
+**/
+int main(
+ int Argc,
+ char *Argv[]
+)
+{
+ EFI_STATUS Status;
+ FIRMWARE_DEVICE *FdData;
+ CHAR8 *InFilePath;
+ CHAR8 FullGuidToolDefinition[_MAX_PATH];
+ CHAR8 *FileName;
+ UINTN FileNameIndex;
+ CHAR8 *PathList;
+ UINTN EnvLen;
+ CHAR8 *NewPathList;
+
+ FdData = NULL;
+ PathList = NULL;
+ NewPathList = NULL;
+ EnvLen = 0;
+
+ if (Argc <= 1) {
+ return -1;
+ }
+ FileName = Argv[0];
+ //
+ // Save, skip filename arg
+ //
+ Argc--;
+ Argv++;
+
+ if ((stricmp(Argv[0], "-v") == 0)) {
+ //
+ // Check the revison of BfmLib
+ // BfmLib -v
+ //
+ printf("%s\n", __BUILD_VERSION);
+ return 1;
+
+ }
+ //
+ // Workaroud: the first call to this function
+ // returns a file name ends with dot
+ //
+#ifndef __GNUC__
+ tmpnam (NULL);
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ close(Fdtmp);
+#endif
+ //
+ // Get the same path with the application itself
+ //
+ if (strlen (FileName) > _MAX_PATH - 1) {
+ Error (NULL, 0, 2000, "Parameter: Input file name is too long", NULL);
+ return -1;
+ }
+ strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1);
+ FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+ FileNameIndex = strlen (FullGuidToolDefinition);
+ while (FileNameIndex != 0) {
+ FileNameIndex --;
+ if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+ FullGuidToolDefinition[FileNameIndex] = 0;
+ break;
+ }
+ }
+ //
+ // Build the path list for Config file scan. The priority is below.
+ // 1. Scan the current path
+ // 2. Scan the same path with the application itself
+ // 3. Scan the current %PATH% of OS environment
+ // 4. Use the build-in default configuration
+ //
+ PathList = getenv("PATH");
+ if (PathList == NULL) {
+ Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
+ return -1;
+ }
+ EnvLen = strlen(PathList);
+ NewPathList = (char *)calloc(
+ strlen (".")
+ + strlen (";")
+ + strlen (FullGuidToolDefinition)
+ + strlen (";")
+ + EnvLen
+ + 1,
+ sizeof(char)
+ );
+ if (NewPathList == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ PathList = NULL;
+ free (PathList);
+ return -1;
+ }
+#ifndef __GNUC__
+ sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList);
+#else
+ sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList);
+#endif
+
+ PathList = NULL;
+ free (PathList);
+ //
+ // Load Guid Tools definition
+ //
+ InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
+ free (NewPathList);
+ if (InFilePath != NULL) {
+ printf ("\nThe Guid Tool Definition of BfmLib comes from the '%s'. \n", InFilePath);
+ mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+ free (InFilePath);
+ } else {
+ //
+ // Use the pre-defined standard guided tools.
+ //
+ printf ("\nThe Guid Tool Definition of BfmLib comes from the build-in default configuration. \n");
+ mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
+ }
+
+ //
+ // BfmLib -e FdName.Fd
+ //
+ if ((stricmp(Argv[0], "-e") == 0)) {
+
+ if (Argc != 2) {
+ return -1;
+ }
+ //
+ // Extract FFS files.
+ //
+ Status = BfmImageView (Argv[1], NULL, FALSE, &FdData);
+
+ if (EFI_ERROR (Status)) {
+ return -1;
+ }
+
+ if (FdData == NULL) {
+ return -1;
+ }
+
+ LibBfmFreeFd(FdData);
+
+ } else if ((stricmp(Argv[0], "-i") == 0)) {
+ //
+ // Insert FFS files to BFV
+ // BfmLib -i InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
+ //
+ if (Argc == 6) {
+ mFvGuidIsSet = TRUE;
+ mFvNameGuidString = Argv[5];
+ StringToGuid (Argv[5], &mFvNameGuid);
+ Argc -= 2;
+ }
+ if (Argc != 4) {
+ return -1;
+ }
+ Status = BfmImageAdd(Argv[1], Argv[2], Argv[3]);
+
+ if (EFI_ERROR (Status)) {
+ return -1;
+ }
+
+ } else if ((stricmp(Argv[0], "-r") == 0)) {
+ //
+ // Replace FFS files in BFV
+ // BfmLib -r InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
+ //
+ if (Argc == 6) {
+ mFvGuidIsSet = TRUE;
+ mFvNameGuidString = Argv[5];
+ StringToGuid (Argv[5], &mFvNameGuid);
+ Argc -= 2;
+ }
+ if (Argc != 4) {
+ return -1;
+ }
+ Status = BfmImageReplace (Argv[1], Argv[2], Argv[3]);
+
+ if (EFI_ERROR (Status)) {
+ return -1;
+ }
+
+ } else {
+ //
+ // Invalid parameter.
+ //
+ return -1;
+ }
+
+ return 1;
+}
+
diff --git a/Platform/Intel/Tools/BfmLib/BinFileManager.h b/Platform/Intel/Tools/BfmLib/BinFileManager.h
new file mode 100644
index 0000000000..ea27f2e8f2
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/BinFileManager.h
@@ -0,0 +1,439 @@
+/** @file
+
+ The header of BinFileManager.c.
+
+Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BIN_FILE_MANAGER_
+#define _BIN_FILE_MANAGER_
+
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FvLib.h>
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Common/PiFirmwareFile.h>
+
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "Compress.h"
+#include "Decompress.h"
+#include "ParseInf.h"
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+#ifdef __GNUC__
+#define OS_SEP '/'
+#define OS_SEP_STR "/"
+#define COPY_STR "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR "rm -r \"%s\" > /dev/null"
+#define DEL_STR "rm \"%s\" > /dev/null"
+#else
+#define OS_SEP '\\'
+#define OS_SEP_STR "\\"
+#define COPY_STR "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR "del \"%s\" > NUL"
+#endif
+
+#define TEMP_DIR_NAME "Temp"
+#define UTILITY_NAME "Binary File Manager (BFM)"
+#define UTILITY_SHORT_NAME "BFM"
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 1
+#define MAX_BASENAME_LEN 60 // not good to HardCode, but let's be reasonable
+#define EFI_SECTION_ERROR EFIERR (100)
+//
+// The maximum number of Pad file guid entries.
+//
+#define MAX_NUMBER_OF_PAD_FILE_GUIDS 1024
+
+//
+// The maximum number of block map entries supported by the library
+//
+#define MAX_NUMBER_OF_FV_BLOCKS 100
+
+
+//
+// The maximum number of sections in an FFS file.
+//
+#define MAX_NUMBER_OF_SECTION_IN_FFS 100
+
+//
+// The maximum number of files in the FV supported by the library
+//
+#define MAX_NUMBER_OF_FILES_IN_FV 1000
+#define MAX_NUMBER_OF_FILES_IN_CAP 1000
+
+
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE is only used by DXE driver.
+///
+#define EFI_DEP_BEFORE 0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER is only used by DXE driver.
+///
+#define EFI_DEP_AFTER 0x01
+
+#define EFI_DEP_PUSH 0x02
+#define EFI_DEP_AND 0x03
+#define EFI_DEP_OR 0x04
+#define EFI_DEP_NOT 0x05
+#define EFI_DEP_TRUE 0x06
+#define EFI_DEP_FALSE 0x07
+#define EFI_DEP_END 0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR 0x09
+
+//
+// INF file strings
+//
+#define OPTIONS_SECTION_STRING "[options]"
+#define ATTRIBUTES_SECTION_STRING "[attributes]"
+#define FILES_SECTION_STRING "[files]"
+#define FV_BASE_ADDRESS_STRING "[FV_BASE_ADDRESS]"
+
+//
+// Options section
+//
+#define EFI_FV_BASE_ADDRESS_STRING "EFI_BASE_ADDRESS"
+#define EFI_FV_FILE_NAME_STRING "EFI_FILE_NAME"
+#define EFI_NUM_BLOCKS_STRING "EFI_NUM_BLOCKS"
+#define EFI_BLOCK_SIZE_STRING "EFI_BLOCK_SIZE"
+#define EFI_GUID_STRING "EFI_GUID"
+#define EFI_FV_FILESYSTEMGUID_STRING "EFI_FV_GUID"
+#define EFI_FV_NAMEGUID_STRING "EFI_FVNAME_GUID"
+#define EFI_CAPSULE_GUID_STRING "EFI_CAPSULE_GUID"
+#define EFI_CAPSULE_HEADER_SIZE_STRING "EFI_CAPSULE_HEADER_SIZE"
+#define EFI_CAPSULE_FLAGS_STRING "EFI_CAPSULE_FLAGS"
+#define EFI_CAPSULE_VERSION_STRING "EFI_CAPSULE_VERSION"
+
+#define EFI_FV_TOTAL_SIZE_STRING "EFI_FV_TOTAL_SIZE"
+#define EFI_FV_TAKEN_SIZE_STRING "EFI_FV_TAKEN_SIZE"
+#define EFI_FV_SPACE_SIZE_STRING "EFI_FV_SPACE_SIZE"
+
+
+typedef UINT32 BFM_ENCAP_TYPE;
+
+#define MAX_LEVEL_IN_FV_FILE 32
+
+//
+// Types of BFM_ENCAP_TREENODE_TYPE
+//
+#define BFM_ENCAP_TREE_FV 0x1
+#define BFM_ENCAP_TREE_FFS 0x2
+#define BFM_ENCAP_TREE_GUIDED_SECTION 0x3
+#define BFM_ENCAP_TREE_COMPRESS_SECTION 0x4
+#define BFM_ENCAP_TREE_FV_SECTION 0x5
+
+extern EFI_HANDLE mParsedGuidedSectionTools;
+extern BOOLEAN mFvGuidIsSet;
+extern EFI_GUID mFvNameGuid;
+
+//
+// Structure to keep a list of GUID-To-BaseNames
+//
+typedef struct _GUID_TO_BASENAME {
+ struct _GUID_TO_BASENAME *Next;
+ INT8 Guid[PRINTED_GUID_BUFFER_SIZE];
+ INT8 BaseName[MAX_BASENAME_LEN];
+} GUID_TO_BASENAME;
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+ EFI_GUID Guid;
+ CHAR8* Name;
+ CHAR8* Path;
+ struct _GUID_SEC_TOOL_ENTRY *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+//
+// Private data types
+//
+//
+// Component information
+//
+typedef struct {
+ UINTN Size;
+ CHAR8 ComponentName[_MAX_PATH];
+} COMPONENT_INFO;
+
+typedef struct {
+ CHAR8 FfsName[_MAX_PATH];
+
+ //
+ // UI Name for this FFS file, if has.
+ //
+ CHAR16 UiName[_MAX_PATH];
+
+ //
+ // Total section number in this FFS.
+ //
+ UINT32 TotalSectionNum;
+
+ //
+ // Describe the position of the FFS file.
+ //
+ UINT8 Level;
+ //
+ // If this FFS has no encapsulate section, this flag will set to True.
+ //
+ BOOLEAN IsLeaf;
+ //
+ // Section type for each section in FFS.
+ //
+ EFI_SECTION_TYPE SectionType[MAX_NUMBER_OF_SECTION_IN_FFS];
+
+}FFS_ATTRIBUTES;
+
+
+typedef struct __ENCAP_INFO_DATA{
+ //
+ // Now Level
+ //
+ UINT8 Level;
+
+ //
+ // Encapsulate type.
+ //
+ BFM_ENCAP_TYPE Type;
+
+ //
+ // Data, if it's FV, should be FV header.
+ //
+ VOID *Data;
+
+ //
+ // if FV ExtHeaderOffset not to zero, should also have FvExtHeader information
+ //
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+
+ //
+ // Next node.
+ //
+ struct __ENCAP_INFO_DATA *NextNode;
+}ENCAP_INFO_DATA;
+
+
+//
+// Contain Offset and Data for PAD FFS contain reset vector or FIT data.
+//
+typedef struct _PATCH_DATA_PAD_FFS {
+ //
+ // The offset of data relative to FV start address;
+ //
+ UINT32 Offset;
+ //
+ // Data
+ //
+ VOID *Data;
+ //
+ // Length of Data
+ //
+ UINT32 Length;
+ //
+ // Next node.
+ //
+ struct _PATCH_DATA_PAD_FFS *NextNode;
+} PATCH_DATA_PAD_FFS;
+
+
+//
+// FV and capsule information holder
+//
+typedef struct _FV_INFOMATION{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+ UINT32 ImageAddress;
+ UINT32 FfsNumbers;
+ CHAR8 FvName[_MAX_PATH];
+ EFI_FV_BLOCK_MAP_ENTRY FvBlocks[MAX_NUMBER_OF_FV_BLOCKS];
+ FFS_ATTRIBUTES FfsAttuibutes[MAX_NUMBER_OF_FILES_IN_FV];
+ EFI_FFS_FILE_HEADER2 FfsHeader[MAX_NUMBER_OF_FILES_IN_FV];
+ struct _FV_INFOMATION *FvNext;
+ ENCAP_INFO_DATA *EncapData;
+ UINT8 FvLevel;
+ PATCH_DATA_PAD_FFS *PatchData;
+ BOOLEAN IsBfvFlag;
+ BOOLEAN IsInputFvFlag;
+
+} FV_INFORMATION;
+
+typedef struct _FIRMWARE_DEVICE {
+ ///
+ /// Size of FD file
+ ///
+ UINT32 Size;
+ FV_INFORMATION *Fv;
+} FIRMWARE_DEVICE;
+
+VOID
+Usage (
+ VOID
+);
+
+
+CHAR8 *
+GenTempFile (
+ VOID
+);
+
+EFI_STATUS
+LibFindFvInFd (
+ IN FILE *InputFile,
+ IN OUT FIRMWARE_DEVICE **FdData
+);
+
+/**
+
+ Add function description
+
+ @param[in] Fv - Firmware Volume to get information from
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+LibGetFvInfo (
+ IN VOID *Fv,
+ IN OUT FV_INFORMATION *CurrentFv,
+ IN CHAR8 *FvName,
+ IN UINT8 Level,
+ IN UINT32 *FfsCount,
+ IN BOOLEAN ViewFlag,
+ IN BOOLEAN IsChildFv
+ );
+
+/*
+ Get size info from FV file.
+
+ @param[in]
+ @param[out]
+
+ @retval
+
+*/
+EFI_STATUS
+LibGetFvSize (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ );
+
+ /**
+
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param[in] ActualSize The size.
+ @param[in] Alignment The desired alignment.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_ABORTED The function encountered an error.
+
+**/
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ );
+
+EFI_STATUS
+LibCreateNewFdCopy(
+ IN CHAR8* OldFd,
+ IN CHAR8* NewFd
+ );
+
+/**
+ Delete a directory and files in it.
+
+ @param[in] DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+ );
+
+
+/**
+
+ Free the whole Fd data structure.
+
+ @param[in] Fd The pointer point to the Fd data structure.
+
+**/
+VOID
+LibBfmFreeFd (
+ FIRMWARE_DEVICE *Fd
+);
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+ VOID
+);
+
+EFI_STATUS
+LibEncapNewFvFile(
+ IN FV_INFORMATION *FvInFd,
+ IN CHAR8 *TemDir,
+ OUT CHAR8 **OutputFile
+);
+
+EFI_STATUS
+LibLocateBfv(
+ IN FIRMWARE_DEVICE *FdData,
+ IN OUT CHAR8 **FvId,
+ IN OUT FV_INFORMATION **FvInFd
+);
+
+/**
+
+ Get the length of a file.
+
+ @param[in] FileName The name of a file.
+
+ @retval The length of file.
+
+**/
+UINT64
+GetFileSize (
+ IN CHAR8 *FileName
+);
+
+/**
+
+ Get the length of BFV PAD file.
+
+ @retval The length of PAD file.
+
+**/
+UINT32
+GetBfvPadSize (
+ VOID
+);
+#endif
diff --git a/Platform/Intel/Tools/BfmLib/GNUmakefile b/Platform/Intel/Tools/BfmLib/GNUmakefile
new file mode 100644
index 0000000000..bd88c58afe
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/GNUmakefile
@@ -0,0 +1,15 @@
+## @file
+# GNU/Linux makefile for 'BfmLib' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = BfmLib
+
+LIBS = -lCommon
+
+OBJECTS = BinFileManager.o BfmLib.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
diff --git a/Platform/Intel/Tools/BfmLib/Makefile b/Platform/Intel/Tools/BfmLib/Makefile
new file mode 100644
index 0000000000..0d10f4ff2d
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/Makefile
@@ -0,0 +1,17 @@
+## @file
+#
+# Windows makefile for 'BfmLib' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent#
+##
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = BfmLib
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = BinFileManager.obj BfmLib.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE
2019-06-21 1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
2019-06-21 1:26 ` [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT Zhang, Shenglei
2019-06-21 1:26 ` [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib Zhang, Shenglei
@ 2019-06-21 1:26 ` Zhang, Shenglei
2019-06-21 1:26 ` [edk2-platform patch 4/6] Platform\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
` (3 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21 1:26 UTC (permalink / raw)
To: devel; +Cc: Bob Feng, Liming Gao
FCE is a tool to retrieve and change HII configuration data in
Firmware Device(*.fd) files.
https://bugzilla.tianocore.org/show_bug.cgi?id=1848
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
Platform/Intel/Tools/FCE/BinaryCreate.c | 216 +
Platform/Intel/Tools/FCE/BinaryCreate.h | 157 +
Platform/Intel/Tools/FCE/BinaryParse.c | 1326 ++++
Platform/Intel/Tools/FCE/BinaryParse.h | 187 +
Platform/Intel/Tools/FCE/Common.c | 2183 ++++++
Platform/Intel/Tools/FCE/Common.h | 999 +++
Platform/Intel/Tools/FCE/Expression.c | 2367 ++++++
Platform/Intel/Tools/FCE/Fce.c | 6449 +++++++++++++++++
Platform/Intel/Tools/FCE/Fce.h | 447 ++
Platform/Intel/Tools/FCE/GNUmakefile | 22 +
Platform/Intel/Tools/FCE/IfrParse.c | 4836 ++++++++++++
Platform/Intel/Tools/FCE/IfrParse.h | 789 ++
Platform/Intel/Tools/FCE/Makefile | 19 +
.../Intel/Tools/FCE/MonotonicBasedVariable.c | 874 +++
.../Intel/Tools/FCE/MonotonicBasedVariable.h | 162 +
Platform/Intel/Tools/FCE/TimeBasedVariable.c | 878 +++
Platform/Intel/Tools/FCE/TimeBasedVariable.h | 166 +
Platform/Intel/Tools/FCE/Variable.c | 1091 +++
Platform/Intel/Tools/FCE/Variable.h | 154 +
Platform/Intel/Tools/FCE/VariableCommon.h | 55 +
20 files changed, 23377 insertions(+)
create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
create mode 100644 Platform/Intel/Tools/FCE/Common.c
create mode 100644 Platform/Intel/Tools/FCE/Common.h
create mode 100644 Platform/Intel/Tools/FCE/Expression.c
create mode 100644 Platform/Intel/Tools/FCE/Fce.c
create mode 100644 Platform/Intel/Tools/FCE/Fce.h
create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
create mode 100644 Platform/Intel/Tools/FCE/Makefile
create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
create mode 100644 Platform/Intel/Tools/FCE/Variable.c
create mode 100644 Platform/Intel/Tools/FCE/Variable.h
create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
diff --git a/Platform/Intel/Tools/FCE/BinaryCreate.c b/Platform/Intel/Tools/FCE/BinaryCreate.c
new file mode 100644
index 0000000000..2f36bc2ef3
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryCreate.c
@@ -0,0 +1,216 @@
+/** @file
+
+ The API to create the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinaryCreate.h"
+#ifndef __GNUC__
+#define GENSEC_RAW "GenSec -s %s \"%s\" -o \"%s\" > NUL"
+#else
+#define GENSEC_RAW "GenSec -s %s \"%s\" -o \"%s\" > /dev/null"
+#endif
+
+//
+// The guid is to for FFS of BFV.
+//
+EFI_GUID gEfiFfsBfvForMultiPlatformGuid = EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID;
+EFI_GUID gEfiFfsBfvForMultiPlatformGuid2 = EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID2;
+
+/**
+ Convert a GUID to a string.
+
+ @param[in] Guid Pointer to GUID to print.
+
+ @return The string after convert.
+**/
+static
+CHAR8 *
+LibBfmGuidToStr (
+ IN EFI_GUID *Guid
+)
+{
+ CHAR8 * Buffer;
+
+ Buffer = NULL;
+
+ if (Guid == NULL) {
+ return NULL;
+ }
+
+ Buffer = (CHAR8 *) malloc (36 + 1);
+
+ if (Buffer == NULL) {
+ return NULL;
+ }
+ memset (Buffer, '\0', 36 + 1);
+
+ sprintf (
+ Buffer,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ Guid->Data1,
+ Guid->Data2,
+ Guid->Data3,
+ Guid->Data4[0],
+ Guid->Data4[1],
+ Guid->Data4[2],
+ Guid->Data4[3],
+ Guid->Data4[4],
+ Guid->Data4[5],
+ Guid->Data4[6],
+ Guid->Data4[7]
+ );
+
+ return Buffer;
+}
+
+/**
+ Create the Ras section in FFS
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] OutputFilePath .te or .pe file
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawSection (
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath
+ )
+{
+ INT32 ReturnValue;
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+ SystemCommand = malloc (
+ strlen (GENSEC_RAW) +
+ strlen ("EFI_SECTION_RAW") +
+ strlen (InputFilePath) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ GENSEC_RAW,
+ "EFI_SECTION_RAW",
+ InputFilePath,
+ OutputFilePath
+ );
+ ReturnValue = system (SystemCommand);
+ free(SystemCommand);
+
+ if (ReturnValue != 0) {
+ printf ("Error. Call GenSec failed.\n");
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Create the Ras type of FFS
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] OutputFilePath .te or .pe file
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawFfs (
+ IN CHAR8** InputFilePaths,
+ IN CHAR8* OutputFilePath,
+ IN BOOLEAN SizeOptimized
+ )
+{
+ INT32 ReturnValue;
+ CHAR8* SystemCommandFormatString;
+ CHAR8* SystemCommand;
+ CHAR8* GuidStr;
+ CHAR8* FilePathFormatStr;
+ CHAR8* FilePathStr;
+ UINT32 Index;
+ UINT32 StrLen;
+ UINT32 Size;
+
+ SystemCommand = NULL;
+ GuidStr = NULL;
+ FilePathStr = NULL;
+ StrLen = 0;
+
+ FilePathFormatStr = " -i \"";
+
+ for (Index = 0; InputFilePaths[Index] != NULL; Index++) {
+ Size = strlen (FilePathFormatStr) + strlen (InputFilePaths[Index]) + 2; // 2 menas "" "
+ if (FilePathStr == NULL) {
+ FilePathStr = malloc (Size);
+ if (NULL == FilePathStr) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ FilePathStr = realloc (FilePathStr, StrLen + Size);
+ if (NULL == FilePathStr) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ memset (FilePathStr + StrLen, ' ', Size);
+ memcpy (FilePathStr + StrLen, FilePathFormatStr, strlen(FilePathFormatStr));
+ memcpy(FilePathStr + StrLen + strlen(FilePathFormatStr), InputFilePaths[Index], strlen(InputFilePaths[Index]));
+ StrLen += Size;
+ *(FilePathStr + StrLen - 2) = '\"';
+ }
+ if (FilePathStr == NULL) {
+ return EFI_ABORTED;
+ }
+ *(FilePathStr + StrLen - 1)= '\0';
+
+
+ if (SizeOptimized) {
+ GuidStr = LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid2);
+ } else {
+ GuidStr = LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid);
+ }
+ if (NULL == GuidStr) {
+ free (FilePathStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SystemCommandFormatString = "GenFfs -t %s %s -g %s -o \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen ("EFI_FV_FILETYPE_FREEFORM") +
+ strlen (FilePathStr) +
+ strlen (GuidStr) +
+ strlen (OutputFilePath) +
+ 1
+ );
+ if (NULL == SystemCommand) {
+ free (GuidStr);
+ free (FilePathStr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ sprintf (
+ SystemCommand,
+ "GenFfs -t %s %s -g %s -o \"%s\"",
+ "EFI_FV_FILETYPE_FREEFORM",// -t
+ FilePathStr, // -i
+ GuidStr, // -g
+ OutputFilePath // -o
+ );
+ ReturnValue = system (SystemCommand);
+ free(SystemCommand);
+ free (FilePathStr);
+ free (GuidStr);
+
+ if (ReturnValue != 0) {
+ printf ("Error. Call GenFfs failed.\n");
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/Tools/FCE/BinaryCreate.h b/Platform/Intel/Tools/FCE/BinaryCreate.h
new file mode 100644
index 0000000000..0e2f22599e
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryCreate.h
@@ -0,0 +1,157 @@
+/** @file
+
+ The API to create the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BINARY_CREATE_H_
+#define _BINARY_CREATE_H_ 1
+
+#include <FvLib.h>
+#include "Compress.h"
+#include "Decompress.h"
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "FirmwareVolumeBufferLib.h"
+#include "OsPath.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "ParseInf.h"
+#include <Common/UefiBaseTypes.h>
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/UefiCapsule.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include <IndustryStandard/PeImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+//1AE42876-008F-4161-B2B7-1C0D15C5EF43
+#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID \
+ { 0x1ae42876, 0x008f, 0x4161, { 0xb2, 0xb7, 0x1c, 0xd, 0x15, 0xc5, 0xef, 0x43 }}
+
+extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid;
+
+// {003E7B41-98A2-4BE2-B27A-6C30C7655225}
+#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID2 \
+ { 0x3e7b41, 0x98a2, 0x4be2, { 0xb2, 0x7a, 0x6c, 0x30, 0xc7, 0x65, 0x52, 0x25 }}
+
+extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid2;
+
+typedef UINT64 SKU_ID;
+
+typedef struct {
+ UINT32 Offset:24;
+ UINT32 Value:8;
+} PCD_DATA_DELTA;
+
+typedef struct {
+ SKU_ID SkuId;
+ UINT16 DefaultId;
+ UINT8 Reserved[6];
+} PCD_DEFAULT_INFO;
+
+typedef struct {
+ //
+ // Full size, it must be at 8 byte alignment.
+ //
+ UINT32 DataSize;
+ //
+ // HeaderSize includes HeaderSize fields and DefaultInfo arrays
+ //
+ UINT32 HeaderSize;
+ //
+ // DefaultInfo arrays those have the same default setting.
+ //
+ PCD_DEFAULT_INFO DefaultInfo[1];
+ //
+ // Default data is stored as variable storage or the array of DATA_DELTA.
+ //
+} PCD_DEFAULT_DATA;
+
+#define PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE SIGNATURE_32('N', 'S', 'D', 'B')
+
+typedef struct {
+ //
+ // PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE
+ //
+ UINT32 Signature;
+ //
+ // Length of the taken default buffer
+ //
+ UINT32 Length;
+ //
+ // Length of the total reserved buffer
+ //
+ UINT32 MaxLength;
+ //
+ // Reserved for 8 byte alignment
+ //
+ UINT32 Reserved;
+ // one or more PCD_DEFAULT_DATA
+} PCD_NV_STORE_DEFAULT_BUFFER_HEADER;
+
+//
+// NvStoreDefaultValueBuffer layout:
+// +-------------------------------------+
+// | PCD_NV_STORE_DEFAULT_BUFFER_HEADER |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (DEFAULT, Standard)|
+// +-------------------------------------+
+// | PCD_DATA_DELTA (DEFAULT, Standard)|
+// +-------------------------------------+
+// | ...... |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (SKU A, Standard) |
+// +-------------------------------------+
+// | PCD_DATA_DELTA (SKU A, Standard) |
+// +-------------------------------------+
+// | ...... |
+// +-------------------------------------+
+//
+
+#pragma pack(1)
+
+typedef struct {
+ UINT16 Offset;
+ UINT8 Value;
+} DATA_DELTA;
+
+#pragma pack()
+
+/**
+ Create the Ras section in FFS
+
+ @param[in] InputFilePath The input file path and name.
+ @param[in] OutputFilePath The output file path and name.
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawSection (
+ IN CHAR8* InputFilePath,
+ IN CHAR8* OutputFilePath
+ );
+
+/**
+ Create the Ras type of FFS
+
+ @param[in] InputFilePath .efi file, it's optional unless process PE/TE section.
+ @param[in] OutputFilePath .te or .pe file
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawFfs (
+ IN CHAR8** InputFilePaths,
+ IN CHAR8* OutputFilePath,
+ IN BOOLEAN SizeOptimized
+ );
+
+#endif
+
diff --git a/Platform/Intel/Tools/FCE/BinaryParse.c b/Platform/Intel/Tools/FCE/BinaryParse.c
new file mode 100644
index 0000000000..e9f8ee6826
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryParse.c
@@ -0,0 +1,1326 @@
+/** @file
+
+ The API to parse the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GNUC__
+#include "windows.h"
+#else
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#endif
+#include "BinaryParse.h"
+#include "BinaryCreate.h"
+#include "VariableCommon.h"
+#include "FirmwareVolumeBufferLib.h"
+
+extern G_EFI_FD_INFO gEfiFdInfo;
+extern EFI_HANDLE mParsedGuidedSectionTools;
+extern CHAR8 mInputFdName[MAX_FILENAME_LEN];
+
+//
+// The Guid to sign the position of Vfr and Uni array in FV
+//
+EFI_GUID gVfrArrayAttractGuid = EFI_VFR_ATTRACT_GUID;
+EFI_GUID gUniStrArrayAttractGuid = EFI_UNI_STR_ATTRACT_GUID;
+EFI_GUID gEfiSystemNvDataFvGuid = EFI_SYSTEM_NVDATA_FV_GUID;
+EFI_GUID gEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
+
+/**
+ Converts a three byte length value into a UINT32.
+
+ @param ThreeByteLength Pointer to the first of the 3 byte length.
+
+ @retval Length Size of the section
+
+**/
+static
+UINT32
+Get3ByteLength (
+ IN UINT8 *ThreeByteLength
+ )
+{
+ UINT32 Length;
+
+ Length = 0;
+
+ if (ThreeByteLength == NULL) {
+ return 0;
+ }
+
+ Length = *((UINT32 *) ThreeByteLength);
+ Length = Length & 0x00FFFFFF;
+
+ return Length;
+}
+
+/**
+ Generate the unique template filename.
+**/
+CHAR8 *
+GenTempFile (
+ VOID
+ )
+{
+ CHAR8 *TemString;
+ TemString = NULL;
+#ifndef __GNUC__
+ TemString = CloneString (tmpnam (NULL));
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ TemString = CloneString(tmp);
+ close(Fdtmp);
+#endif
+ return TemString;
+}
+
+/**
+ Check whether exist the same Ifr FFS. If not existed, return TRUE.
+
+ @param[in] FfsImage The pointer to the binary.
+ @param[in] FileSize The size of binary.
+
+ @return The string after convert.
+**/
+static
+BOOLEAN
+NotExistSameFfsIfr (
+ IN VOID *FfsImage
+)
+{
+ UINT32 Index;
+
+ Index = 0;
+
+ while (gEfiFdInfo.FfsArray[Index] != NULL) {
+ if (memcmp (gEfiFdInfo.FfsArray[Index], FfsImage, sizeof (EFI_GUID)) == 0) {
+ return FALSE;
+ }
+ Index++;
+ }
+ return TRUE;
+}
+
+/**
+ This function returns the next larger size that meets the alignment
+ requirement specified.
+
+ @param ActualSize The size.
+ @param Alignment The desired alignment.
+
+ @retval The Occupied length
+
+**/
+static
+UINT32
+GetOccupiedSize (
+ IN UINT32 ActualSize,
+ IN UINT32 Alignment
+ )
+{
+ UINT32 OccupiedSize;
+
+ OccupiedSize = ActualSize;
+ while ((OccupiedSize & (Alignment - 1)) != 0) {
+ OccupiedSize++;
+ }
+
+ return OccupiedSize;
+}
+
+
+/**
+ Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS.
+
+ @param SectionBuffer The section base address
+ @param BufferLength The length of FFS.
+ @param EfiBufferHeader The structure dual pointer to the efi informations
+
+ @retval EFI_SUCCESS The application exited normally.
+ @retval EFI_ABORTED An error occurred.
+
+**/
+EFI_STATUS
+ParseSection (
+ IN BOOLEAN IsFfsOrEfi,
+ IN OUT UINT8 *SectionBuffer,
+ IN UINT32 BufferLength,
+ IN OUT EFI_SECTION_STRUCT **EfiBufferHeader
+ )
+{
+ UINT32 ParsedLength;
+ EFI_SECTION_TYPE Type;
+ UINT8 *Ptr;
+ UINT32 SectionLength;
+ UINT8 *CompressedBuffer;
+ UINT32 CompressedLength;
+ UINT8 *UncompressedBuffer;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+ DECOMPRESS_FUNCTION DecompressFunction;
+ GETINFO_FUNCTION GetInfoFunction;
+ UINT32 ScratchSize;
+ UINT8 *ScratchBuffer;
+ EFI_STATUS Status;
+ UINT32 DstSize;
+ CHAR8 *ExtractionTool;
+ CHAR8 *ToolInputFile;
+ CHAR8 *ToolOutputFile;
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ UINT8 *ToolOutputBuffer;
+ UINT32 ToolOutputLength;
+ BOOLEAN HasDepexSection;
+
+ Ptr = NULL;
+ SectionLength = 0;
+ CompressedBuffer = NULL;
+ CompressedLength = 0;
+ UncompressedBuffer = NULL;
+ UncompressedLength = 0;
+ CompressionType = 0;
+ ScratchSize = 0;
+ ScratchBuffer = NULL;
+ Status = EFI_SUCCESS;
+ DstSize = 0;
+ ExtractionTool = NULL;
+ ToolInputFile = NULL;
+ ToolOutputFile = NULL;
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+
+ //
+ // Jump the FFS header
+ //
+ if (IsFfsOrEfi) {
+ SectionBuffer = SectionBuffer + sizeof (EFI_FFS_FILE_HEADER);
+ BufferLength = BufferLength - sizeof (EFI_FFS_FILE_HEADER);
+ }
+ ParsedLength = 0;
+ HasDepexSection = FALSE;
+ ExtractionTool = NULL;
+ ToolOutputLength = 0;
+ ToolOutputBuffer = NULL;
+
+ (*EfiBufferHeader)->Length = BufferLength;
+
+ while (ParsedLength < BufferLength) {
+ Ptr = SectionBuffer + ParsedLength;
+
+ SectionLength = Get3ByteLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
+ Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
+
+ //
+ // This is sort of an odd check, but is necessary because FFS files are
+ // padded to a QWORD boundary, meaning there is potentially a whole section
+ // header worth of 0xFF bytes.
+ //
+ if ((SectionLength == 0xffffff) && (Type == 0xff)) {
+ ParsedLength += 4;
+ continue;
+ }
+
+ switch (Type) {
+
+ case EFI_SECTION_PE32:
+ case EFI_SECTION_TE:
+ //
+ //Got the correct address
+ //
+ (*EfiBufferHeader)->BufferBase = (UINTN)(Ptr + sizeof (EFI_COMMON_SECTION_HEADER));
+ return EFI_SUCCESS;
+
+ case EFI_SECTION_RAW:
+ case EFI_SECTION_PIC:
+ break;
+
+ case EFI_SECTION_USER_INTERFACE:
+ HasDepexSection = FALSE;
+ break;
+
+ case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+ case EFI_SECTION_COMPATIBILITY16:
+ case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+ break;
+
+ case EFI_SECTION_PEI_DEPEX:
+ case EFI_SECTION_DXE_DEPEX:
+ case EFI_SECTION_SMM_DEPEX:
+ HasDepexSection = TRUE;
+ break;
+
+ case EFI_SECTION_VERSION:
+ break;
+ case EFI_SECTION_COMPRESSION:
+ UncompressedBuffer = NULL;
+ CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION);
+ UncompressedLength = ((EFI_COMPRESSION_SECTION *) Ptr)->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION *) Ptr)->CompressionType;
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+ if (CompressedLength != UncompressedLength) {
+ Error (
+ NULL,
+ 0,
+ 0,
+ "file is not compressed, but the compressed length does not match the uncompressed length",
+ NULL
+ );
+ return EFI_ABORTED;
+ }
+
+ UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION);
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ GetInfoFunction = EfiGetInfo;
+ DecompressFunction = EfiDecompress;
+ CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION);
+
+ Status = GetInfoFunction (
+ CompressedBuffer,
+ CompressedLength,
+ &DstSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "error getting compression info from compression section", NULL);
+ return EFI_ABORTED;
+ }
+
+ if (DstSize != UncompressedLength) {
+ Error (NULL, 0, 0003, "compression error in the compression section", NULL);
+ return EFI_ABORTED;
+ }
+
+ ScratchBuffer = malloc (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ return EFI_ABORTED;
+ }
+ UncompressedBuffer = malloc (UncompressedLength);
+ if (UncompressedBuffer == NULL) {
+ free (ScratchBuffer);
+ return EFI_ABORTED;
+ }
+ memset (UncompressedBuffer, 0, UncompressedLength);
+
+ Status = DecompressFunction (
+ CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ ScratchBuffer,
+ ScratchSize
+ );
+ free (ScratchBuffer);
+ if (Status != EFI_SUCCESS) {
+ Error (NULL, 0, 0003, "decompress failed", NULL);
+ free (UncompressedBuffer);
+ return EFI_ABORTED;
+ }
+ } else {
+ Error (NULL, 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType);
+ return EFI_ABORTED;
+ }
+
+ Status = ParseSection (FALSE, UncompressedBuffer, UncompressedLength, EfiBufferHeader);
+ if (Status != EFI_SUCCESS) {
+ Error (NULL, 0, 0003, "failed to parse section", NULL);
+ free (UncompressedBuffer);
+ UncompressedBuffer = NULL;
+ } else {
+ return EFI_SUCCESS;
+ }
+ //
+ // Store the allocate memory address for UncompressedBuffer
+ //
+ if (UncompressedBuffer != NULL) {
+ (*EfiBufferHeader)->UncompressedBuffer[(*EfiBufferHeader)->UnCompressIndex] = (UINTN) UncompressedBuffer;
+ (*EfiBufferHeader)->UnCompressIndex = (*EfiBufferHeader)->UnCompressIndex + 1;
+ }
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ //
+ // Decompress failed, and then check for CRC32 sections which we can handle internally if needed.
+ // Maybe this section is no-compressed.
+ //
+ if (!CompareGuid (
+ &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid,
+ &gEfiCrc32GuidedSectionExtractionProtocolGuid
+ )) {
+ //
+ // CRC32 guided section
+ //
+ Status = ParseSection (
+ FALSE,
+ SectionBuffer + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+ BufferLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+ EfiBufferHeader
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of CRC32 GUIDED section failed", NULL);
+ return EFI_ABORTED;
+ } else {
+ return EFI_SUCCESS;
+ }
+ } else {
+ ExtractionTool = LookupGuidedSectionToolPath (
+ mParsedGuidedSectionTools,
+ &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid
+ );
+
+ if (ExtractionTool != NULL) {
+ ToolInputFile = GenTempFile ();
+ ToolOutputFile = GenTempFile ();
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "%s -d -o \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) \
+ + strlen (ExtractionTool) \
+ + strlen (ToolInputFile) \
+ + strlen (ToolOutputFile) \
+ + 1
+ );
+ if (SystemCommand == NULL) {
+ free (ExtractionTool);
+ free (ToolInputFile);
+ free (ToolOutputFile);
+ return EFI_ABORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "%s -d -o \"%s\" \"%s\"",
+ ExtractionTool,
+ ToolOutputFile,
+ ToolInputFile
+ );
+ free (ExtractionTool);
+
+ Status = PutFileImage (
+ ToolInputFile,
+ (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+ SectionLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset
+ );
+
+ if (HasDepexSection) {
+ HasDepexSection = FALSE;
+ }
+
+ system (SystemCommand);
+ remove (ToolInputFile);
+ free (ToolInputFile);
+ ToolInputFile = NULL;
+ free (SystemCommand);
+ SystemCommand = NULL;
+
+ if (EFI_ERROR (Status)) {
+ Error ("FCE", 0, 0004, "unable to decoded GUIDED section", NULL);
+ free (ToolOutputFile);
+ return EFI_ABORTED;
+ }
+
+ Status = GetFileImage (
+ ToolOutputFile,
+ (CHAR8 **)&ToolOutputBuffer,
+ &ToolOutputLength
+ );
+ remove (ToolOutputFile);
+ free (ToolOutputFile);
+ ToolOutputFile = NULL;
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ Status = ParseSection (
+ FALSE,
+ ToolOutputBuffer,
+ ToolOutputLength,
+ EfiBufferHeader
+ );
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+ return EFI_ABORTED;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+ ParsedLength += SectionLength;
+ //
+ // We make then next section begin on a 4-byte boundary
+ //
+ ParsedLength = GetOccupiedSize (ParsedLength, 4);
+ }
+
+ return EFI_ABORTED;
+}
+
+static
+BOOLEAN
+GetNextOffset (
+ IN UINT8 *Data,
+ IN EFI_GUID *Guid,
+ IN UINTN Len,
+ IN OUT UINTN *Offset
+ )
+{
+ UINTN NextOffset;
+ if (*Offset >= Len || Len - *Offset <= sizeof (EFI_GUID)) {
+ return FALSE;
+ }
+
+ for (NextOffset = *Offset; NextOffset < Len - sizeof (EFI_GUID); NextOffset++) {
+ if (CompareGuid(Guid, (EFI_GUID*)(Data + NextOffset)) == 0) {
+ *Offset = NextOffset + sizeof(EFI_GUID);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Get the address by Guid.
+
+ Parse the FFS image, and find the GUID address.There may be some Guids matching the
+ searched Guid.
+
+ @param Fv the Pointer to the image.
+ @param Guid The Guid need to find.
+ @param Offset The dual Pointer to the offset.
+ @param NumOfMatchGuid The number of matching Guid offset.
+
+ @retval EFI_SUCCESS The Search was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+GetAddressByGuid (
+ IN VOID *Fv,
+ IN EFI_GUID *Guid,
+ IN UINTN Len,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchGuid
+ )
+{
+ VOID *LocalFv;
+ UINT8 Flag;
+
+ EFI_RAW_SECTION* Section;
+ UINT8 *RawData;
+ VOID* SectionStart;
+ UINTN NextOffset;
+ UINTN Key;
+ UINTN TotalSectionsSize;
+ UINTN SecLen;
+ UINTN SecHdr;
+ EFI_STATUS Status;
+
+ if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) || Len == 0 ){
+ return EFI_ABORTED;
+ }
+
+ LocalFv = Fv;
+ Flag = 0;
+ Section = NULL;
+ Key = 0;
+
+ if (NumOfMatchGuid != NULL) {
+ *NumOfMatchGuid = 0;
+ }
+
+ SectionStart = (VOID*)((UINTN)LocalFv + FvBufGetFfsHeaderSize(LocalFv));
+ TotalSectionsSize = Len - FvBufGetFfsHeaderSize(LocalFv);
+ while (TRUE) {
+ Status = FvBufFindNextSection (
+ SectionStart,
+ TotalSectionsSize,
+ &Key,
+ (VOID **)&Section
+ );
+ if (Section == NULL || EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (EFI_SECTION_RAW == Section->Type) {
+ if ((*(UINT32 *)Section->Size & 0xffffff) == 0xffffff) {
+ SecLen = ((EFI_RAW_SECTION2 *)Section)->ExtendedSize;
+ SecHdr = sizeof(EFI_RAW_SECTION2);
+ } else {
+ SecLen = *(UINT32 *)Section->Size & 0xffffff;
+ SecHdr = sizeof(EFI_RAW_SECTION);
+ }
+ if (SecLen <= SecHdr || SecLen - SecHdr < sizeof(EFI_GUID)) {
+ continue;
+ }
+ RawData = (UINT8 *)Section + SecHdr;
+ NextOffset = 0;
+ while (GetNextOffset(RawData, Guid, SecLen - SecHdr, &NextOffset)) {
+ Flag = 1;
+ if ((NumOfMatchGuid != NULL) && (Offset != NULL)) {
+ if (*NumOfMatchGuid == 0) {
+ *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ if (*Offset == NULL) {
+ return EFI_ABORTED;
+ }
+ memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ }
+ *(*Offset + *NumOfMatchGuid) = NextOffset + (RawData - (UINT8 *)Fv);
+ (*NumOfMatchGuid)++;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if( Flag == 0 ) {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Search the VfrBin Base address.
+
+ According the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+ @param NumOfMachingOffset the number of Addr (Offset)
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+SearchVfrBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMachingOffset
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN VirOffValue;
+
+ Index = 0;
+ Status = EFI_SUCCESS;
+ VirOffValue = 0;
+
+ if ((Fv == NULL) || (Offset == NULL)) {
+ return EFI_ABORTED;
+ }
+ Status = GetAddressByGuid (
+ Fv,
+ &gVfrArrayAttractGuid,
+ Length,
+ Offset,
+ NumOfMachingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_ABORTED;
+ }
+
+ while (Index < *NumOfMachingOffset) {
+ //
+ // Got the virOffset after the GUID
+ //
+ VirOffValue = *(UINTN *)((UINTN)Fv + *(*Offset + Index));
+ //
+ //Transfer the offset to the VA address. One modules may own more VfrBin address.
+ //
+ *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
+ Index++;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Search the UniBin Base address.
+
+ According the known GUID gUniStrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+
+ @retval Base address Get the address successfully.
+**/
+EFI_STATUS
+SearchUniBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset
+ )
+{
+ UINT8 NumOfMachingOffset;
+ EFI_STATUS Status;
+ UINTN VirOffValue;
+
+ NumOfMachingOffset = 0;
+ Status = EFI_SUCCESS;
+ VirOffValue = 0;
+
+ if ((Fv == NULL) || (Offset == NULL)) {
+ return EFI_ABORTED;
+ }
+ Status = GetAddressByGuid (
+ Fv,
+ &gUniStrArrayAttractGuid,
+ Length,
+ Offset,
+ &NumOfMachingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_ABORTED;
+ }
+ //
+ //Transfer the offset to the VA address. There is only one UniArray in one modules.
+ //
+ if (NumOfMachingOffset == 1) {
+ VirOffValue = *(UINTN *)((UINTN)Fv + **Offset);
+ **Offset = (UINTN) EfiAddr + VirOffValue;
+ } else {
+ printf ("Error. Find more than 1 UniBin in FFS.\n");
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SearchNvStoreDatabaseInFd(
+ IN VOID *Fv,
+ IN UINTN length
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
+ Status = EFI_SUCCESS;
+ Offset = 0;
+ if (Fv == NULL) {
+ printf ("The FV is NULL.");
+ return EFI_ABORTED;
+ }
+ while (Offset < (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER))){
+ NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)((UINT8*)Fv + Offset);
+ if (NvStoreHeader->Signature == PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE) {
+ gEfiFdInfo.ExistNvStoreDatabase = TRUE;
+ gEfiFdInfo.NvStoreDatabase = (UINT8 *) NvStoreHeader;
+ break;
+ }
+ Offset++;
+ }
+ if (Offset == (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) || gEfiFdInfo.ExistNvStoreDatabase != TRUE) {
+ //printf ("Not found the PcdNvStoreDefaultValueBuffer\n");
+ return Status;
+ }
+ return Status;
+}
+
+/**
+ Get the address by Guid.
+
+ Parse the FD image, and find the GUID address.There may be some Guids matching the
+ searched Guid.
+
+ @param Fv the Pointer to the image.
+ @param Guid The Guid need to find.
+ @param Offset The dual Pointer to the offset.
+ @param NumOfMatchGuid The number of matching Guid offset.
+
+ @retval EFI_SUCCESS The Search was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+GetVariableAddressByGuid (
+ IN VOID *Fv,
+ IN EFI_GUID *Guid,
+ IN UINTN Len,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchGuid
+ )
+{
+ UINTN NextOffset;
+ UINT8 Flag;
+
+ if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) ){
+ return EFI_ABORTED;
+ }
+
+ Flag = 0;
+ NextOffset = 0;
+
+ if (NumOfMatchGuid != NULL) {
+ *NumOfMatchGuid = 0;
+ }
+ while (GetNextOffset(Fv, Guid, Len, &NextOffset)) {
+ Flag = 1;
+ if (NumOfMatchGuid != NULL && Offset != NULL) {
+ if (*NumOfMatchGuid == 0) {
+ *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ if (*Offset == NULL) {
+ return EFI_ABORTED;
+ }
+ memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ }
+ *(*Offset + *NumOfMatchGuid) = NextOffset;
+ (*NumOfMatchGuid)++;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if( Flag == 0 ) {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Search the EFI Variable Base address.
+
+ According the known GUID gEfiSystemNvDataFvGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+ @param NumOfMachingOffset the number of IFR array in one FFS
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_ABORTED An error occured.
+**/
+EFI_STATUS
+SearchEfiVarInFFS (
+ IN VOID *Fv,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMachingOffset
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+
+ if ((Fv == NULL) || (Offset == NULL)) {
+ printf ("The FV or offset is NULL.");
+ return EFI_ABORTED;
+ }
+ Status = GetVariableAddressByGuid (
+ Fv,
+ &gEfiSystemNvDataFvGuid,
+ Length,
+ Offset,
+ NumOfMachingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return EFI_ABORTED;
+ }
+ //
+ //Transfer the offset to the VA address.
+ //
+ while (Index < *NumOfMachingOffset) {
+ *(*Offset + Index) = (UINTN) Fv + *(*Offset + Index);
+ Index++;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse the Ffs header to get the size.
+
+ @param InputFile The pointer to the input file
+ @param FvSize The pointer to the file size
+
+ @return EFI_SUCCESS Get the file size successfully
+**/
+EFI_STATUS
+ReadFfsHeader (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+ EFI_FFS_FILE_HEADER FfsHeader;
+ EFI_FV_FILETYPE Type;
+
+ //
+ // Check input parameters
+ //
+ if ((InputFile == NULL) || (FvSize == NULL)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Read the header
+ //
+ fread (
+ &FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER),
+ 1,
+ InputFile
+ );
+ Type = FfsHeader.Type;
+
+ if (Type == EFI_FV_FILETYPE_DRIVER) {
+ *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+ } else if (Type == EFI_FV_FILETYPE_APPLICATION) {
+ *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+ } else if (Type == EFI_FV_FILETYPE_FREEFORM) {
+ *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+ } else {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/*
+ Read the length of the whole FD
+
+ This function determines the size of the FV.
+
+ @param InputFile The file that contains the FV image.
+ @param FvSize The size of the FV.
+
+ @retval EFI_SUCCESS The application exited normally.
+ @retval EFI_ABORTED An error occurred.
+
+**/
+static
+EFI_STATUS
+ReadFdHeader (
+ IN FILE *InputFile,
+ OUT UINT32 *FvSize
+ )
+{
+ //
+ // Check input parameters
+ //
+ if ((InputFile == NULL) || (FvSize == NULL)) {
+ return EFI_ABORTED;
+ }
+ *FvSize = 0;
+ //
+ // Get the total size of FD file (Fixed the length)
+ //
+ fseek(InputFile,0,SEEK_END);
+ *FvSize = ftell(InputFile);
+ fseek(InputFile,0,SEEK_SET);
+
+ if (*FvSize == 0) {
+ return EFI_ABORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the file to memory.
+
+ @param InputFile The file that contains the FV image.
+ @param Size The size of the file.
+
+ @retval The pointer to the begining position of memory.
+**/
+VOID *
+ReadFileToMemory (
+ IN CHAR8 *FileName,
+ OUT UINT32 *Size
+ )
+{
+ FILE *InFile;
+ VOID *Address;
+ UINT32 BytesRead;
+ EFI_STATUS Status;
+
+ InFile = NULL;
+ Address = NULL;
+ BytesRead = 0;
+ Status = EFI_SUCCESS;
+
+ InFile = fopen (FileName,"rb");
+ if (InFile == NULL) {
+ return NULL;
+ }
+ //
+ // Determine the size of FV
+ //
+ Status = ReadFdHeader (InFile, Size);
+ if (Status != EFI_SUCCESS) {
+ fclose (InFile);
+ return NULL;
+ }
+ //
+ // Allocate a buffer for the FV image
+ //
+ Address = malloc (*Size);
+ if (Address == NULL) {
+ fclose (InFile);
+ return NULL;
+ }
+ memset (Address, 0, *Size);
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (InFile, 0, SEEK_SET);
+ BytesRead = fread (Address, 1, *Size, InFile);
+ fclose (InFile);
+ if ((UINTN) BytesRead != *Size) {
+ free (Address);
+ return NULL;
+ }
+ return Address;
+}
+
+/**
+ Search the EFI variables address in Fd.
+
+ Open and read the *.fd to the memory, initialize the global structure.
+ Update the EFI variables addr and the begining position of memory.
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+GetEfiVariablesAddr (
+ BOOLEAN UqiIsSet
+ )
+{
+ VOID *FdImage;
+ UINT32 FdSize;
+ EFI_STATUS Status;
+ UINTN *EfiVarAddr;
+ UINT8 NumOfMachingVar;
+ UINT32 Index;
+ BOOLEAN GotFlag;
+ EFI_FIRMWARE_VOLUME_HEADER *Variable;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+ BOOLEAN NormalOrNot;
+
+ FdImage = NULL;
+ FdSize = 0;
+ Status = EFI_SUCCESS;
+ EfiVarAddr = NULL;
+ NumOfMachingVar = 0;
+ Index = 0;
+ GotFlag = TRUE;
+ Variable = NULL;
+
+ FdImage = ReadFileToMemory (mInputFdName, &FdSize);
+ if (FdImage == NULL) {
+ return EFI_ABORTED;
+ }
+ if (!UqiIsSet) {
+ Status = SearchNvStoreDatabaseInFd(FdImage, FdSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ Status = SearchEfiVarInFFS (
+ FdImage,
+ FdSize,
+ &EfiVarAddr,
+ &NumOfMachingVar
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Check the signature "_FVH"
+ //
+ Index = 0;
+ GotFlag = FALSE;
+
+ while (Index < NumOfMachingVar) {
+ Variable = (EFI_FIRMWARE_VOLUME_HEADER *)(*(EfiVarAddr + Index) - 0x20);
+ if (Variable->Signature == 0x4856465F) {
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore ((UINT8 *)Variable + Variable->HeaderLength);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
+ NormalOrNot = CheckNormalVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
+ if (AuthencitatedMonotonicOrNot || AuthencitatedBasedTimeOrNot || NormalOrNot) {
+ GotFlag = TRUE;
+ gEfiFdInfo.EfiVariableAddr = (UINTN)Variable;
+ break;
+ }
+ }
+ Index++;
+ }
+ free (EfiVarAddr);
+ if (!GotFlag) {
+ return EFI_ABORTED;
+ }
+ gEfiFdInfo.Fd = FdImage;
+ gEfiFdInfo.FdSize = FdSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pick up the FFS which includes IFR section.
+
+ Parse all FFS extracted by BfmLib, and save all which includes IFR
+ Binary to gEfiFdInfo structure.
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated.
+ @retval EFI_ABORTED Read FFS Failed.
+**/
+EFI_STATUS
+FindFileInFolder (
+ IN CHAR8 *FolderName,
+ OUT BOOLEAN *ExistStorageInBfv,
+ OUT BOOLEAN *SizeOptimized
+)
+{
+ CHAR8 *FileName;
+ CHAR8 *CurFolderName;
+ EFI_STATUS Status;
+ UINTN MaxFileNameLen;
+ UINTN Index;
+ CHAR8 FileNameArry[MAX_FILENAME_LEN];
+ FILE *FfsFile;
+ UINTN FileSize;
+ VOID *FfsImage;
+ UINTN BytesRead;
+#ifndef __GNUC__
+ HANDLE FindHandle;
+ WIN32_FIND_DATA FindFileData;
+#else
+ struct dirent *pDirent;
+ DIR *pDir;
+#endif
+
+ FileName = NULL;
+ CurFolderName = NULL;
+ Status = EFI_SUCCESS;
+ MaxFileNameLen = 0;
+ Index = 0;
+ FileSize = 0;
+ BytesRead = 0;
+ FfsImage = NULL;
+ FfsFile = NULL;
+
+ MaxFileNameLen = strlen (FolderName) + MAX_FILENAME_LEN;
+ CurFolderName = (CHAR8 *)calloc(
+ strlen (FolderName) + strlen (OS_SEP_STR) + strlen ("*.*")+ 1,
+ sizeof(CHAR8)
+ );
+ if (CurFolderName == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ strcpy (CurFolderName, FolderName);
+ strcat (CurFolderName, OS_SEP_STR);
+ strcat (CurFolderName, "*.*");
+ FileName = (CHAR8 *)calloc(
+ MaxFileNameLen,
+ sizeof(CHAR8)
+ );
+ if (FileName == NULL) {
+ free (CurFolderName);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+#ifndef __GNUC__
+ if((FindHandle = FindFirstFile(CurFolderName, &FindFileData)) != INVALID_HANDLE_VALUE){
+ do {
+ memset (FileName, 0, MaxFileNameLen);
+ if ((strcmp (FindFileData.cFileName, ".") == 0)
+ || (strcmp (FindFileData.cFileName, "..") == 0)
+ ) {
+ continue;
+ }
+ if (strlen(FolderName) + strlen ("\\") + strlen (FindFileData.cFileName) > MAX_FILENAME_LEN - 1) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ snprintf (FileNameArry, MAX_FILENAME_LEN, "%s%c%s", FolderName, OS_SEP, FindFileData.cFileName);
+ FfsFile = fopen (FileNameArry, "rb");
+ if (FfsFile == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
+ if (EFI_ERROR (Status)) {
+ fclose (FfsFile);
+ Status = EFI_SUCCESS;
+ continue;
+ }
+ //
+ // Allocate a buffer for the FFS file
+ //
+ FfsImage = malloc (FileSize);
+ if (FfsImage == NULL) {
+ fclose (FfsFile);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (FfsFile, 0, SEEK_SET);
+ BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
+ fclose (FfsFile);
+
+ if ((UINTN) BytesRead != FileSize) {
+ free (FfsImage);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Check whether exists the storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = FALSE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether exists the optimized storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = TRUE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether current FFS includes IFR
+ //
+ Status = GetAddressByGuid (
+ FfsImage,
+ &gVfrArrayAttractGuid,
+ FileSize,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ free (FfsImage);
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Check whether existed same IFR binary. If existed, not insert the new one.
+ //
+ if (NotExistSameFfsIfr (FfsImage)) {
+ gEfiFdInfo.FfsArray[Index] = FfsImage;
+ gEfiFdInfo.Length[Index++] = FileSize;
+ }
+ }
+
+ } while (FindNextFile (FindHandle, &FindFileData));
+ FindClose(FindHandle);
+ } else {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+Done:
+ free (CurFolderName);
+ free (FileName);
+
+#else
+ if((pDir = opendir(FolderName)) != NULL){
+ while ((pDirent = readdir(pDir)) != NULL){
+ memset (FileName, 0, MaxFileNameLen);
+ if ((strcmp (pDirent->d_name, ".") == 0)
+ || (strcmp (pDirent->d_name, "..") == 0)
+ ) {
+ continue;
+ }
+ sprintf (FileNameArry, "%s%c%s", FolderName, OS_SEP, pDirent->d_name);
+ FfsFile = fopen (FileNameArry, "rb");
+ Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
+ if (EFI_ERROR (Status)) {
+ fclose (FfsFile);
+ Status = EFI_SUCCESS;
+ continue;
+ }
+ //
+ // Allocate a buffer for the FFS file
+ //
+ FfsImage = malloc (FileSize);
+ if (FfsImage == NULL) {
+ fclose (FfsFile);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+ //
+ // Seek to the start of the image, then read the entire FV to the buffer
+ //
+ fseek (FfsFile, 0, SEEK_SET);
+ BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
+ fclose (FfsFile);
+
+ if ((UINTN) BytesRead != FileSize) {
+ free (FfsImage);
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Check whether exists the storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = FALSE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether exists the optimized storage ffs in BFV for multi-platform mode
+ //
+ if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
+ *ExistStorageInBfv = TRUE;
+ *SizeOptimized = TRUE;
+ gEfiFdInfo.StorageFfsInBfv = FfsImage;
+ continue;
+ }
+ //
+ // Check whether current FFS includes IFR
+ //
+ Status = GetAddressByGuid (
+ FfsImage,
+ &gVfrArrayAttractGuid,
+ FileSize,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ free (FfsImage);
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Check whether existed same IFR binary. If existed, not insert the new one.
+ //
+ if (NotExistSameFfsIfr (FfsImage)) {
+ gEfiFdInfo.FfsArray[Index] = FfsImage;
+ gEfiFdInfo.Length[Index++] = FileSize;
+ }
+ }
+
+ }
+ closedir(pDir);
+ } else {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+Done:
+ free (CurFolderName);
+ free (FileName);
+#endif
+ return Status;
+}
+
diff --git a/Platform/Intel/Tools/FCE/BinaryParse.h b/Platform/Intel/Tools/FCE/BinaryParse.h
new file mode 100644
index 0000000000..a3995b8b79
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryParse.h
@@ -0,0 +1,187 @@
+/** @file
+
+ The API to parse the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _BINARY_PARSE_H_
+#define _BINARY_PARSE_H_ 1
+
+#include <FvLib.h>
+#include "Compress.h"
+#include "Decompress.h"
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "FirmwareVolumeBufferLib.h"
+#include "OsPath.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "ParseInf.h"
+#include <Common/UefiBaseTypes.h>
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/UefiCapsule.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include <IndustryStandard/PeImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+#ifdef __GNUC__
+#define OS_SEP '/'
+#define OS_SEP_STR "/"
+#else
+#define OS_SEP '\\'
+#define OS_SEP_STR "\\"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#define TEMP_DIR_NAME "Temp"
+#define MAX_FILENAME_LEN 200
+#define MAX_MATCH_GUID_NUM 100
+#define MAX_EFI_IN_FFS_NUM 100
+
+typedef struct {
+ VOID *Fd;
+ UINT32 FdSize;
+ UINTN EfiVariableAddr;
+ UINTN Length[MAX_EFI_IN_FFS_NUM];
+ VOID *FfsArray[MAX_EFI_IN_FFS_NUM];
+ VOID *StorageFfsInBfv;
+ VOID *NvStoreDatabase;
+ BOOLEAN ExistNvStoreDatabase;
+} G_EFI_FD_INFO;
+
+///
+///Define the structure for th sections
+///
+typedef struct {
+ UINTN BufferBase;
+ UINTN UncompressedBuffer[MAX_EFI_IN_FFS_NUM];
+ UINTN Length;
+ UINT8 UnCompressIndex;
+} EFI_SECTION_STRUCT;
+
+// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
+#define EFI_VFR_ATTRACT_GUID \
+{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }
+
+// {8913C5E0-33F6-4d86-9BF1-43EF89FC0666}
+#define EFI_UNI_STR_ATTRACT_GUID \
+{ 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
+
+// {FFF12B8D-7696-4C8B-A985-2747075B4F50}
+#define EFI_SYSTEM_NVDATA_FV_GUID \
+{ 0xFFF12B8D, 0x7696, 0x4C8B, { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+
+/**
+ Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS.
+
+ @param SectionBuffer The section base address
+ @param BufferLength The length of FFS.
+ @param EfiBufferHeader The structure dual pointer to the efi informations
+
+ @retval EFI_SUCCESS The application exited normally.
+ @retval EFI_ABORTED An error occurred.
+
+**/
+EFI_STATUS
+ParseSection (
+ IN BOOLEAN IsFfsOrEfi,
+ IN OUT UINT8 *SectionBuffer,
+ IN UINT32 BufferLength,
+ IN OUT EFI_SECTION_STRUCT **EfiBufferHeader
+ );
+
+/**
+ Search the VfrBin Base address.
+
+ According the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+ @param NumOfMachingOffset the number of Addr (Offset)
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+SearchVfrBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMachingOffset
+ );
+
+/**
+ Search the UniBin Base address.
+
+ According the known GUID gUniStrArrayAttractGuid to get the base address from FFS.
+
+ @param Fv the Pointer to the FFS
+ @param EfiAddr the Pointer to the EFI in FFS
+ @param Length the length of Fv
+ @param Offset the Pointer to the Addr (Offset)
+
+ @retval Base address Get the address successfully.
+**/
+EFI_STATUS
+SearchUniBinInFFS (
+ IN VOID *Fv,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset
+ );
+
+/**
+ Read the file to memory.
+
+ @param InputFile The file that contains the FV image.
+ @param Size The size of the file.
+
+ @retval The pointer to the begining position of memory.
+**/
+VOID *
+ReadFileToMemory (
+ IN CHAR8 *FileName,
+ OUT UINT32 *Size
+ );
+
+/**
+ Search the EFI variables address in Fd.
+
+ Open and read the *.fd to the memory, initialize the global structure.
+ Update the EFI variables addr and the begining position of memory.
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+EFI_STATUS
+GetEfiVariablesAddr (
+ BOOLEAN UqiIsSet
+ );
+
+/**
+ Pick up the FFS which includes IFR section.
+
+ Parse all FFS extracted by BfmLib, and save all which includes IFR
+ Binary to gEfiFdInfo structure.
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated.
+ @retval EFI_ABORTED Read FFS Failed.
+**/
+EFI_STATUS
+FindFileInFolder (
+ IN CHAR8 *FolderName,
+ OUT BOOLEAN *ExistStorageInBfv,
+ OUT BOOLEAN *SizeOptimized
+);
+
+#endif
+
diff --git a/Platform/Intel/Tools/FCE/Common.c b/Platform/Intel/Tools/FCE/Common.c
new file mode 100644
index 0000000000..9b14a24a9b
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Common.c
@@ -0,0 +1,2183 @@
+/** @file
+
+ Common library.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "Common.h"
+
+#define WARNING_STATUS_NUMBER 4
+#define ERROR_STATUS_NUMBER 24
+
+CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+CONST CHAR8 *mStatusString[] = {
+ "Success", // RETURN_SUCCESS = 0
+ "Warning Unknown Glyph", // RETURN_WARN_UNKNOWN_GLYPH = 1
+ "Warning Delete Failure", // RETURN_WARN_DELETE_FAILURE = 2
+ "Warning Write Failure", // RETURN_WARN_WRITE_FAILURE = 3
+ "Warning Buffer Too Small", // RETURN_WARN_BUFFER_TOO_SMALL = 4
+ "Load Error", // RETURN_LOAD_ERROR = 1 | MAX_BIT
+ "Invalid Parameter", // RETURN_INVALID_PARAMETER = 2 | MAX_BIT
+ "Unsupported", // RETURN_UNSUPPORTED = 3 | MAX_BIT
+ "Bad Buffer Size", // RETURN_BAD_BUFFER_SIZE = 4 | MAX_BIT
+ "Buffer Too Small", // RETURN_BUFFER_TOO_SMALL, = 5 | MAX_BIT
+ "Not Ready", // RETURN_NOT_READY = 6 | MAX_BIT
+ "Device Error", // RETURN_DEVICE_ERROR = 7 | MAX_BIT
+ "Write Protected", // RETURN_WRITE_PROTECTED = 8 | MAX_BIT
+ "Out of Resources", // RETURN_OUT_OF_RESOURCES = 9 | MAX_BIT
+ "Volume Corrupt", // RETURN_VOLUME_CORRUPTED = 10 | MAX_BIT
+ "Volume Full", // RETURN_VOLUME_FULL = 11 | MAX_BIT
+ "No Media", // RETURN_NO_MEDIA = 12 | MAX_BIT
+ "Media changed", // RETURN_MEDIA_CHANGED = 13 | MAX_BIT
+ "Not Found", // RETURN_NOT_FOUND = 14 | MAX_BIT
+ "Access Denied", // RETURN_ACCESS_DENIED = 15 | MAX_BIT
+ "No Response", // RETURN_NO_RESPONSE = 16 | MAX_BIT
+ "No mapping", // RETURN_NO_MAPPING = 17 | MAX_BIT
+ "Time out", // RETURN_TIMEOUT = 18 | MAX_BIT
+ "Not started", // RETURN_NOT_STARTED = 19 | MAX_BIT
+ "Already started", // RETURN_ALREADY_STARTED = 20 | MAX_BIT
+ "Aborted", // RETURN_ABORTED = 21 | MAX_BIT
+ "ICMP Error", // RETURN_ICMP_ERROR = 22 | MAX_BIT
+ "TFTP Error", // RETURN_TFTP_ERROR = 23 | MAX_BIT
+ "Protocol Error" // RETURN_PROTOCOL_ERROR = 24 | MAX_BIT
+};
+
+/**
+ Copies one Null-terminated Unicode string to another Null-terminated Unicode
+ string and returns the new Unicode string.
+
+ This function copies the contents of the Unicode string Source to the Unicode
+ string Destination, and returns Destination. If Source and Destination
+ overlap, then the results are undefined.
+
+ If Destination is NULL, then return NULL.
+ If Destination is not aligned on a 16-bit boundary, then return NULL.
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCpy (
+ OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ )
+{
+ CHAR16 *ReturnValue;
+
+ ReturnValue = NULL;
+
+ if ((Destination == NULL) || ((UINTN) Destination % 2 != 0)) {
+ return NULL;
+ }
+
+ ReturnValue = Destination;
+ while (*Source != 0) {
+ *(Destination++) = *(Source++);
+ }
+ *Destination = 0;
+ return ReturnValue;
+}
+
+/**
+ Returns the length of a Null-terminated Unicode string.
+
+ This function returns the number of Unicode characters in the Null-terminated
+ Unicode string specified by String.
+
+ If String is NULL, then return 0.
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The length of String.
+
+**/
+UINTN
+FceStrLen (
+ IN CONST CHAR16 *String
+ )
+{
+ UINTN Length;
+
+ if (String == NULL) {
+ return 0;
+ }
+ for (Length = 0; *String != L'\0'; String++, Length++) {
+ ;
+ }
+ return Length;
+}
+
+/**
+ Returns the size of a Null-terminated Unicode string in bytes, including the
+ Null terminator.
+
+ This function returns the size, in bytes, of the Null-terminated Unicode string
+ specified by String.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The size of String.
+
+**/
+UINTN
+FceStrSize (
+ IN CONST CHAR16 *String
+ )
+{
+ return (FceStrLen (String) + 1) * sizeof (*String);
+}
+
+/**
+ Compares two Null-terminated Unicode strings, and returns the difference
+ between the first mismatched Unicode characters.
+
+ This function compares the Null-terminated Unicode string FirstString to the
+ Null-terminated Unicode string SecondString. If FirstString is identical to
+ SecondString, then 0 is returned. Otherwise, the value returned is the first
+ mismatched Unicode character in SecondString subtracted from the first
+ mismatched Unicode character in FirstString.
+
+ @param FirstString A pointer to a Null-terminated Unicode string.
+ @param SecondString A pointer to a Null-terminated Unicode string.
+
+ @retval 0 FirstString is identical to SecondString.
+ @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+FceStrCmp (
+ IN CONST CHAR16 *FirstString,
+ IN CONST CHAR16 *SecondString
+ )
+{
+ while ((*FirstString != L'\0') && (*FirstString == *SecondString)) {
+ FirstString++;
+ SecondString++;
+ }
+ return *FirstString - *SecondString;
+}
+
+/**
+ Concatenates one Null-terminated Unicode string to another Null-terminated
+ Unicode string, and returns the concatenated Unicode string.
+
+ This function concatenates two Null-terminated Unicode strings. The contents
+ of Null-terminated Unicode string Source are concatenated to the end of
+ Null-terminated Unicode string Destination. The Null-terminated concatenated
+ Unicode String is returned. If Source and Destination overlap, then the
+ results are undefined.
+
+ If Destination is NULL, then ASSERT().
+ If Destination is not aligned on a 16-bit boundary, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+ than PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+ and Source results in a Unicode string with more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCat (
+ IN OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ )
+{
+ StrCpy (Destination + FceStrLen (Destination), Source);
+
+ //
+ // Size of the resulting string should never be zero.
+ // PcdMaximumUnicodeStringLength is tested inside FceStrLen().
+ //
+ ASSERT (FceStrSize (Destination) != 0);
+ return Destination;
+}
+
+/**
+ Returns the first occurrence of a Null-terminated Unicode sub-string
+ in a Null-terminated Unicode string.
+
+ This function scans the contents of the Null-terminated Unicode string
+ specified by String and returns the first occurrence of SearchString.
+ If SearchString is not found in String, then NULL is returned. If
+ the length of SearchString is zero, then String is
+ returned.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If SearchString is NULL, then ASSERT().
+ If SearchString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and SearchString
+ or String contains more than PcdMaximumUnicodeStringLength Unicode
+ characters, not including the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+ @param SearchString A pointer to a Null-terminated Unicode string to search for.
+
+ @retval NULL If the SearchString does not appear in String.
+ @return others If there is a match.
+
+**/
+CHAR16 *
+StrStr (
+ IN CONST CHAR16 *String,
+ IN CONST CHAR16 *SearchString
+ )
+{
+ CONST CHAR16 *FirstMatch;
+ CONST CHAR16 *SearchStringTmp;
+
+ //
+ // ASSERT both strings are less long than PcdMaximumUnicodeStringLength.
+ // Length tests are performed inside FceStrLen().
+ //
+ ASSERT (FceStrSize (String) != 0);
+ ASSERT (FceStrSize (SearchString) != 0);
+
+ if (*SearchString == L'\0') {
+ return (CHAR16 *) String;
+ }
+
+ while (*String != L'\0') {
+ SearchStringTmp = SearchString;
+ FirstMatch = String;
+
+ while ((*String == *SearchStringTmp)
+ && (*String != L'\0')) {
+ String++;
+ SearchStringTmp++;
+ }
+
+ if (*SearchStringTmp == L'\0') {
+ return (CHAR16 *) FirstMatch;
+ }
+
+ if (*String == L'\0') {
+ return NULL;
+ }
+
+ String = FirstMatch + 1;
+ }
+
+ return NULL;
+}
+
+/**
+ Convert one Null-terminated ASCII string to a Null-terminated
+ Unicode string and returns the Unicode string.
+
+ This function converts the contents of the ASCII string Source to the Unicode
+ string Destination, and returns Destination. The function terminates the
+ Unicode string Destination by appending a Null-terminator character at the end.
+ The caller is responsible to make sure Destination points to a buffer with size
+ equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
+
+ @param Source A pointer to a Null-terminated ASCII string.
+ @param Destination A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+ @return NULL If Destination or Source is NULL, return NULL.
+
+**/
+CHAR16 *
+AsciiStrToUnicodeStr (
+ IN CONST CHAR8 *Source,
+ OUT CHAR16 *Destination
+ )
+{
+ CHAR16 *ReturnValue;
+
+ ReturnValue = NULL;
+
+ if ((Destination == NULL) || (Source == NULL) || (strlen (Source) == 0)) {
+ return NULL;
+ }
+ ReturnValue = Destination;
+ while (*Source != '\0') {
+ *(Destination++) = (CHAR16) *(Source++);
+ }
+ //
+ // End the Destination with a NULL.
+ //
+ *Destination = '\0';
+
+ return ReturnValue;
+}
+
+/**
+ Internal function that convert a number to a string in Buffer.
+
+ Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
+
+ @param Buffer Location to place the ASCII string of Value.
+ @param Value The value to convert to a Decimal or Hexadecimal string in Buffer.
+ @param Radix Radix of the value
+
+ @return A pointer to the end of buffer filled with ASCII string.
+
+**/
+CHAR8 *
+BasePrintLibValueToString (
+ IN OUT CHAR8 *Buffer,
+ IN INT64 Value,
+ IN UINTN Radix
+ )
+{
+ UINT32 Remainder;
+
+ //
+ // Loop to convert one digit at a time in reverse order
+ //
+ *Buffer = 0;
+ do {
+ Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
+ *(++Buffer) = mHexStr[Remainder];
+ } while (Value != 0);
+
+ //
+ // Return pointer of the end of filled buffer.
+ //
+ return Buffer;
+}
+
+/**
+ Reads a 16-bit value from memory that may be unaligned.
+
+ This function returns the 16-bit value pointed to by Buffer. The function
+ guarantees that the read operation does not produce an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 16-bit value that may be unaligned.
+
+ @return The 16-bit value read from Buffer.
+
+**/
+UINT16
+FceReadUnaligned16 (
+ IN CONST UINT16 *Buffer
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer;
+}
+
+/**
+ Reads a 32-bit value from memory that may be unaligned.
+
+ This function returns the 32-bit value pointed to by Buffer. The function
+ guarantees that the read operation does not produce an alignment fault.
+
+ If the Buffer is NULL, then ASSERT().
+
+ @param Buffer A pointer to a 32-bit value that may be unaligned.
+
+ @return The 32-bit value read from Buffer.
+
+**/
+UINT32
+ReadUnaligned32 (
+ IN CONST UINT32 *Buffer
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return *Buffer;
+}
+
+/**
+ Internal function that places the character into the Buffer.
+
+ Internal function that places ASCII or Unicode character into the Buffer.
+
+ @param Buffer The buffer to place the Unicode or ASCII string.
+ @param EndBuffer The end of the input Buffer. No characters will be
+ placed after that.
+ @param Length The count of character to be placed into Buffer.
+ (Negative value indicates no buffer fill.)
+ @param Character The character to be placed into Buffer.
+ @param Increment The character increment in Buffer.
+
+ @return Buffer.
+
+**/
+CHAR8 *
+BasePrintLibFillBuffer (
+ OUT CHAR8 *Buffer,
+ IN CHAR8 *EndBuffer,
+ IN INTN Length,
+ IN UINTN Character,
+ IN INTN Increment
+ )
+{
+ INTN Index;
+
+ for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
+ *Buffer = (CHAR8) Character;
+ if (Increment != 1) {
+ *(Buffer + 1) = (CHAR8)(Character >> 8);
+ }
+ Buffer += Increment;
+ }
+
+ return Buffer;
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and a VA_LIST argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine.
+
+ If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
+
+ @param[out] Buffer The character buffer to print the results of the
+ parsing of Format into.
+ @param[in] BufferSize The maximum number of characters to put into
+ buffer.
+ @param[in] Flags Initial flags value.
+ Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
+ and COUNT_ONLY_NO_PRINT set.
+ @param[in] Format A Null-terminated format string.
+ @param[in] VaListMarker VA_LIST style variable argument list consumed by
+ processing Format.
+ @param[in] BaseListMarker BASE_LIST style variable argument list consumed
+ by processing Format.
+
+ @return The number of characters printed not including the Null-terminator.
+ If COUNT_ONLY_NO_PRINT was set returns the same, but without any
+ modification to Buffer.
+
+**/
+UINTN
+BasePrintLibSPrintMarker (
+ OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker, OPTIONAL
+ IN BASE_LIST BaseListMarker OPTIONAL
+ )
+{
+ CHAR8 *OriginalBuffer;
+ CHAR8 *EndBuffer;
+ CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
+ UINT32 BytesPerOutputCharacter;
+ UINTN BytesPerFormatCharacter;
+ UINTN FormatMask;
+ UINTN FormatCharacter;
+ UINTN Width;
+ UINTN Precision;
+ INT64 Value;
+ CONST CHAR8 *ArgumentString;
+ UINTN Character;
+ EFI_GUID *TmpGuid;
+ TIME *TmpTime;
+ UINTN Count;
+ UINTN ArgumentMask;
+ INTN BytesPerArgumentCharacter;
+ UINTN ArgumentCharacter;
+ BOOLEAN Done;
+ UINTN Index;
+ CHAR8 Prefix;
+ BOOLEAN ZeroPad;
+ BOOLEAN Comma;
+ UINTN Digits;
+ UINTN Radix;
+ RETURN_STATUS Status;
+ UINT32 GuidData1;
+ UINT16 GuidData2;
+ UINT16 GuidData3;
+ UINTN LengthToReturn;
+
+ //
+ // If you change this code be sure to match the 2 versions of this function.
+ // Nearly identical logic is found in the BasePrintLib and
+ // DxePrintLibPrint2Protocol (both PrintLib instances).
+ //
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ if (BufferSize == 0) {
+ Buffer = NULL;
+ }
+ } else {
+ //
+ // We can run without a Buffer for counting only.
+ //
+ if (BufferSize == 0) {
+ return 0;
+ }
+ ASSERT (Buffer != NULL);
+ }
+
+ if ((Flags & OUTPUT_UNICODE) != 0) {
+ BytesPerOutputCharacter = 2;
+ } else {
+ BytesPerOutputCharacter = 1;
+ }
+
+ LengthToReturn = 0;
+
+ //
+ // Reserve space for the Null terminator.
+ //
+ BufferSize--;
+ OriginalBuffer = Buffer;
+
+ //
+ // Set the tag for the end of the input Buffer.
+ //
+ EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;
+
+ if ((Flags & FORMAT_UNICODE) != 0) {
+ //
+ // Make sure format string cannot contain more than PcdMaximumUnicodeStringLength
+ // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+ //
+ ASSERT (FceStrSize ((CHAR16 *) Format) != 0);
+ BytesPerFormatCharacter = 2;
+ FormatMask = 0xffff;
+ } else {
+ //
+ // Make sure format string cannot contain more than PcdMaximumAsciiStringLength
+ // Ascii characters if PcdMaximumAsciiStringLength is not zero.
+ //
+ ASSERT (strlen (Format) + 1 != 0);
+ BytesPerFormatCharacter = 1;
+ FormatMask = 0xff;
+ }
+
+ //
+ // Get the first character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+
+ //
+ // Loop until the end of the format string is reached or the output buffer is full
+ //
+ while (FormatCharacter != 0 && Buffer < EndBuffer) {
+ //
+ // Clear all the flag bits except those that may have been passed in
+ //
+ Flags &= (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
+
+ //
+ // Set the default width to zero, and the default precision to 1
+ //
+ Width = 0;
+ Precision = 1;
+ Prefix = 0;
+ Comma = FALSE;
+ ZeroPad = FALSE;
+ Count = 0;
+ Digits = 0;
+
+ switch (FormatCharacter) {
+ case '%':
+ //
+ // Parse Flags and Width
+ //
+ for (Done = FALSE; !Done; ) {
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ switch (FormatCharacter) {
+ case '.':
+ Flags |= PRECISION;
+ break;
+ case '-':
+ Flags |= LEFT_JUSTIFY;
+ break;
+ case '+':
+ Flags |= PREFIX_SIGN;
+ break;
+ case ' ':
+ Flags |= PREFIX_BLANK;
+ break;
+ case ',':
+ Flags |= COMMA_TYPE;
+ break;
+ case 'L':
+ case 'l':
+ Flags |= LONG_TYPE;
+ break;
+ case '*':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ if (BaseListMarker == NULL) {
+ Width = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Width = BASE_ARG (BaseListMarker, UINTN);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Precision = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Precision = BASE_ARG (BaseListMarker, UINTN);
+ }
+ }
+ break;
+ case '0':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PREFIX_ZERO;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ for (Count = 0; ((FormatCharacter >= '0') && (FormatCharacter <= '9')); ){
+ Count = (Count * 10) + FormatCharacter - '0';
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ }
+ Format -= BytesPerFormatCharacter;
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ Width = Count;
+ } else {
+ Precision = Count;
+ }
+ break;
+
+ case '\0':
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format -= BytesPerFormatCharacter;
+ Precision = 0;
+ //
+ // break skipped on purpose.
+ //
+ default:
+ Done = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Handle each argument type
+ //
+ switch (FormatCharacter) {
+ case 'p':
+ //
+ // Flag space, +, 0, L & l are invalid for type p.
+ //
+ Flags &= ~(PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE);
+ if (sizeof (VOID *) > 4) {
+ Flags |= LONG_TYPE;
+ }
+ case 'X':
+ Flags |= PREFIX_ZERO;
+ //
+ // break skipped on purpose
+ //
+ case 'x':
+ Flags |= RADIX_HEX;
+ //
+ // break skipped on purpose
+ //
+ case 'd':
+ if ((Flags & LONG_TYPE) == 0) {
+ //
+ // 'd','x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "int" is used in this one case.
+ //
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, int);
+ } else {
+ Value = BASE_ARG (BaseListMarker, int);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, INT64);
+ } else {
+ Value = BASE_ARG (BaseListMarker, INT64);
+ }
+ }
+ if ((Flags & PREFIX_BLANK) != 0) {
+ Prefix = ' ';
+ }
+ if ((Flags & PREFIX_SIGN) != 0) {
+ Prefix = '+';
+ }
+ if ((Flags & COMMA_TYPE) != 0) {
+ Comma = TRUE;
+ }
+ if ((Flags & RADIX_HEX) == 0) {
+ Radix = 10;
+ if (Comma) {
+ Flags &= (~PREFIX_ZERO);
+ Precision = 1;
+ }
+ if (Value < 0) {
+ Flags |= PREFIX_SIGN;
+ Prefix = '-';
+ Value = -Value;
+ }
+ } else {
+ Radix = 16;
+ Comma = FALSE;
+ if ((Flags & LONG_TYPE) == 0 && Value < 0) {
+ //
+ // 'd','x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "unsigned int" is used in this one case.
+ //
+ Value = (unsigned int)Value;
+ }
+ }
+ //
+ // Convert Value to a reversed string
+ //
+ Count = BasePrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
+ if (Value == 0 && Precision == 0) {
+ Count = 0;
+ }
+ ArgumentString = (CHAR8 *)ValueBuffer + Count;
+
+ Digits = Count % 3;
+ if (Digits != 0) {
+ Digits = 3 - Digits;
+ }
+ if (Comma && Count != 0) {
+ Count += ((Count - 1) / 3);
+ }
+ if (Prefix != 0) {
+ Count++;
+ Precision++;
+ }
+ Flags |= ARGUMENT_REVERSED;
+ ZeroPad = TRUE;
+ if ((Flags & PREFIX_ZERO) != 0) {
+ if ((Flags & LEFT_JUSTIFY) == 0) {
+ if ((Flags & PAD_TO_WIDTH) != 0) {
+ if ((Flags & PRECISION) == 0) {
+ Precision = Width;
+ }
+ }
+ }
+ }
+ break;
+
+ case 's':
+ case 'S':
+ Flags |= ARGUMENT_UNICODE;
+ //
+ // break skipped on purpose
+ //
+ case 'a':
+ if (BaseListMarker == NULL) {
+ ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
+ } else {
+ ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
+ }
+ if (ArgumentString == NULL) {
+ Flags &= (~ARGUMENT_UNICODE);
+ ArgumentString = "<null string>";
+ }
+ //
+ // Set the default precision for string to be zero if not specified.
+ //
+ if ((Flags & PRECISION) == 0) {
+ Precision = 0;
+ }
+ break;
+
+ case 'c':
+ if (BaseListMarker == NULL) {
+ Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
+ } else {
+ Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
+ }
+ ArgumentString = (CHAR8 *)&Character;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+
+ case 'g':
+ if (BaseListMarker == NULL) {
+ TmpGuid = VA_ARG (VaListMarker, EFI_GUID *);
+ } else {
+ TmpGuid = BASE_ARG (BaseListMarker, EFI_GUID *);
+ }
+ if (TmpGuid == NULL) {
+ ArgumentString = "<null guid>";
+ } else {
+ GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
+ GuidData2 = FceReadUnaligned16 (&(TmpGuid->Data2));
+ GuidData3 = FceReadUnaligned16 (&(TmpGuid->Data3));
+ BasePrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ GuidData1,
+ GuidData2,
+ GuidData3,
+ TmpGuid->Data4[0],
+ TmpGuid->Data4[1],
+ TmpGuid->Data4[2],
+ TmpGuid->Data4[3],
+ TmpGuid->Data4[4],
+ TmpGuid->Data4[5],
+ TmpGuid->Data4[6],
+ TmpGuid->Data4[7]
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 't':
+ if (BaseListMarker == NULL) {
+ TmpTime = VA_ARG (VaListMarker, TIME *);
+ } else {
+ TmpTime = BASE_ARG (BaseListMarker, TIME *);
+ }
+ if (TmpTime == NULL) {
+ ArgumentString = "<null time>";
+ } else {
+ BasePrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%02d/%02d/%04d %02d:%02d",
+ TmpTime->Month,
+ TmpTime->Day,
+ TmpTime->Year,
+ TmpTime->Hour,
+ TmpTime->Minute
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 'r':
+ if (BaseListMarker == NULL) {
+ Status = VA_ARG (VaListMarker, RETURN_STATUS);
+ } else {
+ Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
+ }
+ ArgumentString = ValueBuffer;
+ if (RETURN_ERROR (Status)) {
+ //
+ // Clear error bit
+ //
+ Index = Status & ~MAX_BIT;
+ if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
+ }
+ } else {
+ Index = Status;
+ if (Index <= WARNING_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index];
+ }
+ }
+ if (ArgumentString == ValueBuffer) {
+ BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '%':
+ default:
+ //
+ // if the type is '%' or unknown, then print it to the screen
+ //
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ default:
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+
+ //
+ // Retrieve the ArgumentString attriubutes
+ //
+ if ((Flags & ARGUMENT_UNICODE) != 0) {
+ ArgumentMask = 0xffff;
+ BytesPerArgumentCharacter = 2;
+ } else {
+ ArgumentMask = 0xff;
+ BytesPerArgumentCharacter = 1;
+ }
+ if ((Flags & ARGUMENT_REVERSED) != 0) {
+ BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
+ } else {
+ //
+ // Compute the number of characters in ArgumentString and store it in Count
+ // ArgumentString is either null-terminated, or it contains Precision characters
+ //
+ for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {
+ ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
+ if (ArgumentCharacter == 0) {
+ break;
+ }
+ }
+ }
+
+ if (Precision < Count) {
+ Precision = Count;
+ }
+
+ //
+ // Pad before the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ if (ZeroPad) {
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
+ }
+ } else {
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
+ }
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ }
+
+ //
+ // Output the Prefix character if it is present
+ //
+ Index = 0;
+ if (Prefix != 0) {
+ Index++;
+ }
+
+ //
+ // Copy the string into the output buffer performing the required type conversions
+ //
+ while (Index < Count) {
+ ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;
+
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
+ }
+ ArgumentString += BytesPerArgumentCharacter;
+ Index++;
+ if (Comma) {
+ Digits++;
+ if (Digits == 3) {
+ Digits = 0;
+ Index++;
+ if (Index < Count) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Pad after the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ }
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ return (LengthToReturn / BytesPerOutputCharacter);
+ }
+
+ ASSERT (Buffer != NULL);
+ //
+ // Null terminate the Unicode or ASCII string
+ //
+ BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
+ //
+ // Make sure output buffer cannot contain more than PcdMaximumUnicodeStringLength
+ // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+ //
+ ASSERT ((((Flags & OUTPUT_UNICODE) == 0)) || (FceStrSize ((CHAR16 *) OriginalBuffer) != 0));
+ //
+ // Make sure output buffer cannot contain more than PcdMaximumAsciiStringLength
+ // ASCII characters if PcdMaximumAsciiStringLength is not zero.
+ //
+ ASSERT ((((Flags & OUTPUT_UNICODE) != 0)) || ((strlen (OriginalBuffer) + 1) != 0));
+
+ return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and variable argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine
+
+ @param StartOfBuffer The character buffer to print the results of the parsing
+ of Format into.
+ @param BufferSize The maximum number of characters to put into buffer.
+ Zero means no limit.
+ @param Flags Initial flags value.
+ Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+ @param FormatString A Null-terminated format string.
+ @param ... The variable argument list.
+
+ @return The number of characters printed.
+
+**/
+UINTN
+BasePrintLibSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+
+ VA_START (Marker, FormatString);
+ return BasePrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on
+ a Null-terminated Unicode format string and a VA_LIST argument list
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+UnicodeVSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ ASSERT_UNICODE_BUFFER (StartOfBuffer);
+ ASSERT_UNICODE_BUFFER (FormatString);
+ return BasePrintLibSPrintMarker ((CHAR8 *)StartOfBuffer, BufferSize >> 1, FORMAT_UNICODE | OUTPUT_UNICODE, (CHAR8 *)FormatString, Marker, NULL);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+UnicodeSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+
+ VA_START (Marker, FormatString);
+ return UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Convert a Null-terminated Unicode string to a Null-terminated
+ ASCII string and returns the ASCII string.
+
+ This function converts the content of the Unicode string Source
+ to the ASCII string Destination by copying the lower 8 bits of
+ each Unicode character. It returns Destination. The function terminates
+ the ASCII string Destination by appending a Null-terminator character
+ at the end. The caller is responsible to make sure Destination points
+ to a buffer with size equal or greater than (FceStrLen (Source) + 1) in bytes.
+
+ If Destination is NULL, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+
+ If any Unicode characters in Source contain non-zero value in
+ the upper 8 bits, then ASSERT().
+
+ @param Source Pointer to a Null-terminated Unicode string.
+ @param Destination Pointer to a Null-terminated ASCII string.
+
+ @reture Destination
+
+**/
+CHAR8 *
+UnicodeStrToAsciiStr (
+ IN CONST CHAR16 *Source,
+ OUT CHAR8 *Destination
+ )
+{
+ CHAR8 *ReturnValue;
+
+ ReturnValue = Destination;
+ assert (Destination != NULL);
+ assert (Source != NULL);
+ assert (((UINTN) Source & 0x01) == 0);
+
+ while (*Source != L'\0') {
+ //
+ // If any Unicode characters in Source contain
+ // non-zero value in the upper 8 bits, then ASSERT().
+ //
+ assert (*Source < 0x100);
+ *(ReturnValue++) = (CHAR8) *(Source++);
+ }
+
+ *ReturnValue = '\0';
+
+ return Destination;
+}
+
+/**
+ Allocate new memory and then copy the Unicode string Source to Destination.
+
+ @param Dest Location to copy string
+ @param Src String to copy
+
+**/
+VOID
+NewStringCpy (
+ IN OUT CHAR16 **Dest,
+ IN CHAR16 *Src
+ )
+{
+ if (*Dest != NULL) {
+ FreePool (*Dest);
+ }
+ *Dest = FceAllocateCopyPool (FceStrSize (Src), Src);
+ ASSERT (*Dest != NULL);
+}
+
+/**
+ Check if a Unicode character is a decimal character.
+
+ This internal function checks if a Unicode character is a
+ decimal character. The valid decimal character is from
+ L'0' to L'9'.
+
+ @param Char The character to check against.
+
+ @retval TRUE If the Char is a decmial character.
+ @retval FALSE If the Char is not a decmial character.
+
+**/
+BOOLEAN
+FceInternalIsDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN) ((Char >= L'0') && (Char <= L'9'));
+}
+
+/**
+ Convert a Unicode character to upper case only if
+ it maps to a valid small-case ASCII character.
+
+ This internal function only deal with Unicode character
+ which maps to a valid small-case ASCII character, i.e.
+ L'a' to L'z'. For other Unicode character, the input character
+ is returned directly.
+
+ @param Char The character to convert.
+
+ @retval LowerCharacter If the Char is with range L'a' to L'z'.
+ @retval Unchanged Otherwise.
+
+**/
+CHAR16
+FceInternalCharToUpper (
+ IN CHAR16 Char
+ )
+{
+ if ((Char >= L'a') && (Char <= L'z')) {
+ return (CHAR16) (Char - (L'a' - L'A'));
+ }
+
+ return Char;
+}
+
+/**
+ Convert a Unicode character to numerical value.
+
+ This internal function only deal with Unicode character
+ which maps to a valid hexadecimal ASII character, i.e.
+ L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
+ Unicode character, the value returned does not make sense.
+
+ @param Char The character to convert.
+
+ @return The numerical value converted.
+
+**/
+UINTN
+FceInternalHexCharToUintn (
+ IN CHAR16 Char
+ )
+{
+ if (FceInternalIsDecimalDigitCharacter (Char)) {
+ return Char - L'0';
+ }
+
+ return (UINTN) (10 + FceInternalCharToUpper (Char) - L'A');
+}
+
+/**
+ Check if a Unicode character is a hexadecimal character.
+
+ This internal function checks if a Unicode character is a
+ decimal character. The valid hexadecimal character is
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
+
+
+ @param Char The character to check against.
+
+ @retval TRUE If the Char is a hexadecmial character.
+ @retval FALSE If the Char is not a hexadecmial character.
+
+**/
+BOOLEAN
+FceInternalIsHexaDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+
+ return (BOOLEAN) (FceInternalIsDecimalDigitCharacter (Char) ||
+ ((Char >= L'A') && (Char <= L'F')) ||
+ ((Char >= L'a') && (Char <= L'f')));
+}
+
+
+/**
+ Convert a Null-terminated Unicode decimal string to a value of
+ type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a decimal number. The format
+ of the input Unicode string String is:
+
+ [spaces] [decimal digits].
+
+ The valid decimal digit character is in the range [0-9]. The
+ function will ignore the pad space, which includes spaces or
+ tab characters, before [decimal digits]. The running zero in the
+ beginning of [decimal digits] will be ignored. Then, the function
+ stops at the first character that is a not a valid decimal character
+ or a Null-terminator, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then 0 is returned.
+ If String has no pad spaces or valid decimal digits,
+ then 0 is returned.
+ If the number represented by String overflows according
+ to the range defined by UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains
+ more than PcdMaximumUnicodeStringLength Unicode characters, not including
+ the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrDecimalToUint64 (
+ IN CONST CHAR16 *String
+ )
+{
+ UINT64 Result;
+
+ //
+ // ASSERT String is less long than PcdMaximumUnicodeStringLength.
+ // Length tests are performed inside FceStrLen().
+ //
+ ASSERT (FceStrSize (String) != 0);
+
+ //
+ // Ignore the pad spaces (space or tab)
+ //
+ while ((*String == L' ') || (*String == L'\t')) {
+ String++;
+ }
+
+ //
+ // Ignore leading Zeros after the spaces
+ //
+ while (*String == L'0') {
+ String++;
+ }
+
+ Result = 0;
+
+ while (FceInternalIsDecimalDigitCharacter (*String)) {
+ //
+ // If the number represented by String overflows according
+ // to the range defined by UINTN, then ASSERT().
+ //
+ ASSERT (Result <= DivU64x32 (((UINT64) ~0) - (*String - L'0') , 10));
+
+ Result = MultU64x32 (Result, 10) + (*String - L'0');
+ String++;
+ }
+
+ return Result;
+}
+
+
+/**
+ Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a hexadecimal number.
+ The format of the input Unicode string String is
+
+ [spaces][zeros][x][hexadecimal digits].
+
+ The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+ The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+ If "x" appears in the input string, it must be prefixed with at least one 0.
+ The function will ignore the pad space, which includes spaces or tab characters,
+ before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+ [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+ first valid hexadecimal digit. Then, the function stops at the first character that is
+ a not a valid hexadecimal character or NULL, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then zero is returned.
+ If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+ then zero is returned.
+ If the number represented by String overflows according to the range defined by
+ UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+ then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrHexToUint64 (
+ IN CONST CHAR16 *String
+ )
+{
+ UINT64 Result;
+
+ //
+ // ASSERT String is less long than PcdMaximumUnicodeStringLength.
+ // Length tests are performed inside FceStrLen().
+ //
+ ASSERT (FceStrSize (String) != 0);
+
+ //
+ // Ignore the pad spaces (space or tab)
+ //
+ while ((*String == L' ') || (*String == L'\t')) {
+ String++;
+ }
+
+ //
+ // Ignore leading Zeros after the spaces
+ //
+ while (*String == L'0') {
+ String++;
+ }
+
+ if (FceInternalCharToUpper (*String) == L'X') {
+ ASSERT (*(String - 1) == L'0');
+ if (*(String - 1) != L'0') {
+ return 0;
+ }
+ //
+ // Skip the 'X'
+ //
+ String++;
+ }
+
+ Result = 0;
+
+ while (FceInternalIsHexaDecimalDigitCharacter (*String)) {
+ //
+ // If the Hex Number represented by String overflows according
+ // to the range defined by UINTN, then ASSERT().
+ //
+ ASSERT (Result <= RShiftU64 (((UINT64) ~0) - FceInternalHexCharToUintn (*String) , 4));
+
+ Result = LShiftU64 (Result, 4);
+ Result = Result + FceInternalHexCharToUintn (*String);
+ String++;
+ }
+
+ return Result;
+}
+
+
+CHAR16
+ToUpper (
+ CHAR16 a
+ )
+{
+ if (('a' <= a) && (a <= 'z')) {
+ return (CHAR16) (a - 0x20);
+ } else {
+ return a;
+ }
+}
+
+CHAR16
+ToLower (
+ CHAR16 a
+ )
+{
+ if (('A' <= a) && (a <= 'Z')) {
+ return (CHAR16) (a + 0x20);
+ } else {
+ return a;
+ }
+}
+
+/**
+ Performs a case-insensitive comparison between a Null-terminated
+ Unicode pattern string and a Null-terminated Unicode string.
+
+ @param String - A pointer to a Null-terminated Unicode string.
+ @param Pattern - A pointer to a Null-terminated Unicode pattern string.
+
+
+ @retval TRUE - Pattern was found in String.
+ @retval FALSE - Pattern was not found in String.
+
+**/
+BOOLEAN
+MetaiMatch (
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ )
+{
+ CHAR16 c;
+ CHAR16 p;
+
+ assert (String != NULL);
+ assert (Pattern != NULL);
+
+ for (;;) {
+ p = *Pattern;
+ Pattern += 1;
+
+ if (p == 0) {
+ //
+ // End of pattern. If end of string, TRUE match
+ //
+ if (*String) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+ } else {
+
+ c = *String;
+ if (ToUpper (c) != ToUpper (p)) {
+ return FALSE;
+ }
+
+ String += 1;
+
+ }
+
+ }
+
+}
+/**
+ Multiplies a 64-bit unsigned integer by a 32-bit unsigned integer and
+ generates a 64-bit unsigned result.
+
+ This function multiplies the 64-bit unsigned value Multiplicand by the 32-bit
+ unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+ bit unsigned result is returned.
+
+ @param Multiplicand A 64-bit unsigned value.
+ @param Multiplier A 32-bit unsigned value.
+
+ @return Multiplicand * Multiplier.
+
+**/
+UINT64
+MultU64x32 (
+ IN UINT64 Multiplicand,
+ IN UINT32 Multiplier
+ )
+{
+ return Multiplicand * Multiplier;
+}
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. This
+ function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32 (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor
+ )
+{
+ ASSERT (Divisor != 0);
+ return Dividend / Divisor;
+}
+
+/**
+ Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
+ with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the left by Count bits. The
+ low Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift left.
+ @param Count The number of bits to shift left.
+
+ @return Operand << Count.
+
+**/
+UINT64
+LShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ )
+{
+ ASSERT (Count < 64);
+ return Operand << Count;
+}
+
+/**
+ Shifts a 64-bit integer right between 0 and 63 bits. This high bits are
+ filled with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the right by Count bits. The
+ high Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift right.
+ @param Count The number of bits to shift right.
+
+ @return Operand >> Count.
+
+**/
+UINT64
+RShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ )
+
+{
+ ASSERT (Count < 64);
+ return Operand >> Count;
+}
+
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result and an optional 32-bit unsigned remainder.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+ is not NULL, then the 32-bit unsigned remainder is returned in Remainder.
+ This function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+ @param Remainder A pointer to a 32-bit unsigned value. This parameter is
+ optional and may be NULL.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32Remainder (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor,
+ OUT UINT32 *Remainder
+ )
+{
+ ASSERT (Divisor != 0);
+
+ if (Remainder != NULL) {
+ *Remainder = (UINT32)(Dividend % Divisor);
+ }
+ return Dividend / Divisor;
+}
+
+/**
+ Copies a buffer to an allocated buffer.
+
+ Allocates the number bytes specified by AllocationSize, copies allocationSize bytes
+ from Buffer to the newly allocated buffer, and returns a pointer to the allocated
+ buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+FceAllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ Memory = NULL;
+
+ if ((Buffer == NULL) || (AllocationSize == 0)) {
+ return Memory;
+ }
+
+ Memory = calloc (AllocationSize, sizeof (CHAR8));
+ if (Memory != NULL) {
+ Memory = memcpy (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Initializes the head node of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Initializes the forward and backward links of a new linked list. After
+ initializing a linked list with this function, the other linked list
+ functions may be used to add and remove nodes from the linked list. It is up
+ to the caller of this function to allocate the memory for ListHead.
+
+ If ListHead is NULL, then ASSERT().
+
+ @param ListHead A pointer to the head node of a new doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InitializeListHead (
+ IN OUT LIST_ENTRY *ListHead
+ )
+
+{
+ assert (ListHead != NULL);
+
+ ListHead->ForwardLink = ListHead;
+ ListHead->BackLink = ListHead;
+ return ListHead;
+}
+
+/**
+ Adds a node to the beginning of a doubly-linked list, and returns the pointer
+ to the head node of the doubly-linked list.
+
+ Adds the node Entry at the beginning of the doubly-linked list denoted by
+ ListHead, and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be inserted at the beginning
+ of a doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertHeadList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ )
+{
+ assert ((ListHead != NULL) && (Entry != NULL));
+
+ Entry->ForwardLink = ListHead->ForwardLink;
+ Entry->BackLink = ListHead;
+ Entry->ForwardLink->BackLink = Entry;
+ ListHead->ForwardLink = Entry;
+ return ListHead;
+}
+
+/**
+ Adds a node to the end of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Adds the node Entry to the end of the doubly-linked list denoted by ListHead,
+ and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be added at the end of the
+ doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertTailList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ )
+{
+ assert ((ListHead != NULL) && (Entry != NULL));
+
+ Entry->ForwardLink = ListHead;
+ Entry->BackLink = ListHead->BackLink;
+ Entry->BackLink->ForwardLink = Entry;
+ ListHead->BackLink = Entry;
+ return ListHead;
+}
+
+/**
+ Retrieves the first node of a doubly-linked list.
+
+ Returns the first node of a doubly-linked list. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+ If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+
+ @return The first node of a doubly-linked list.
+ @retval NULL The list is empty.
+
+**/
+LIST_ENTRY *
+GetFirstNode (
+ IN CONST LIST_ENTRY *List
+ )
+{
+ assert (List != NULL);
+
+ return List->ForwardLink;
+}
+
+/**
+ Retrieves the next node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that follows Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the next node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetNextNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return Node->ForwardLink;
+}
+
+/**
+ Retrieves the previous node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that precedes Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the previous node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetPreviousNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return Node->BackLink;
+}
+
+/**
+ Checks to see if a doubly-linked list is empty or not.
+
+ Checks to see if the doubly-linked list is empty. If the linked list contains
+ zero nodes, this function returns TRUE. Otherwise, it returns FALSE.
+
+ If ListHead is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+
+ @retval TRUE The linked list is empty.
+ @retval FALSE The linked list is not empty.
+
+**/
+BOOLEAN
+IsListEmpty (
+ IN CONST LIST_ENTRY *ListHead
+ )
+{
+ assert (ListHead != NULL);
+
+ return (BOOLEAN)(ListHead->ForwardLink == ListHead);
+}
+
+/**
+ Determines if a node in a doubly-linked list is the head node of a the same
+ doubly-linked list. This function is typically used to terminate a loop that
+ traverses all the nodes in a doubly-linked list starting with the head node.
+
+ Returns TRUE if Node is equal to List. Returns FALSE if Node is one of the
+ nodes in the doubly-linked list specified by List. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),
+ then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List and Node is not
+ equal to List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the head of the doubly-linked list pointed by List.
+ @retval FALSE Node is not the head of the doubly-linked list pointed by List.
+
+**/
+BOOLEAN
+IsNull (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return (BOOLEAN)(Node == List);
+}
+
+/**
+ Determines if a node the last node in a doubly-linked list.
+
+ Returns TRUE if Node is the last node in the doubly-linked list specified by
+ List. Otherwise, FALSE is returned. List must have been initialized with
+ INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the last node in the linked list.
+ @retval FALSE Node is not the last node in the linked list.
+
+**/
+BOOLEAN
+IsNodeAtEnd (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ )
+{
+ assert ((List != NULL) && (Node != NULL));
+
+ return (BOOLEAN)(!IsNull (List, Node) && (List->BackLink == Node));
+}
+
+/**
+ Removes a node from a doubly-linked list, and returns the node that follows
+ the removed node.
+
+ Removes the node Entry from a doubly-linked list. It is up to the caller of
+ this function to release the memory used by this node if that is required. On
+ exit, the node following Entry in the doubly-linked list is returned. If
+ Entry is the only node in the linked list, then the head node of the linked
+ list is returned.
+
+ If Entry is NULL, then ASSERT().
+ If Entry is the head node of an empty list, then ASSERT().
+ If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+ linked list containing Entry, including the Entry node, is greater than
+ or equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param Entry A pointer to a node in a linked list.
+
+ @return Entry.
+
+**/
+LIST_ENTRY *
+RemoveEntryList (
+ IN CONST LIST_ENTRY *Entry
+ )
+{
+ assert (!IsListEmpty (Entry));
+
+ Entry->ForwardLink->BackLink = Entry->BackLink;
+ Entry->BackLink->ForwardLink = Entry->ForwardLink;
+ return Entry->ForwardLink;
+}
+
diff --git a/Platform/Intel/Tools/FCE/Common.h b/Platform/Intel/Tools/FCE/Common.h
new file mode 100644
index 0000000000..6b21974878
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Common.h
@@ -0,0 +1,999 @@
+/** @file
+
+ Common library.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _COMMON_LIB_H_
+#define _COMMON_LIB_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+#include "CommonLib.h"
+#include <Common/UefiBaseTypes.h>
+
+#define MAX_QUI_PARAM_LEN 2000
+#define ERROR_INFO_LENGTH 400
+#define MAX_STR_LEN_FOR_PICK_UQI 200
+#define MAX_PLATFORM_DEFAULT_ID_NUM 1000
+#define _MAX_BUILD_VERSION 100
+#define _MAXIMUM_SECTION_FILE_NUM 1000
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+///
+/// Variable attributes.
+///
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+
+///
+/// This attribute is identified by the mnemonic 'HR'
+/// elsewhere in this specification.
+///
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
+
+#define VARSTORE_LIST_TYPE 0x0000000000000001ULL
+#define EFI_VARSTORE_LIST_TYPE 0x0000000000000002ULL
+#define PLATFORM_DEFAULT_ID_TYPE 0x0000000000000004ULL
+#define UQI_LIST_TYPE 0x0000000000000008ULL
+#define HII_OBJ_LIST_TYPE 0x0000000000000010ULL
+
+///
+/// LIST_ENTRY structure definition.
+///
+typedef struct _LIST_ENTRY {
+ struct _LIST_ENTRY *ForwardLink;
+ struct _LIST_ENTRY *BackLink;
+} LIST_ENTRY;
+
+#define CR(Record, TYPE, Field, TestSignature) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))
+#define AllocateZeroPool(a) calloc(a, sizeof (CHAR8))
+#define FreePool(a) free(a)
+#define CopyMem(a, b, c) memcpy(a, b, c)
+#define ZeroMem(a, b) memset(a, 0, b)
+#define CompareMem(a, b, c) memcmp(a, b, c)
+#define AllocatePool(a) malloc(a)
+
+/**
+ Returns a 16-bit signature built from 2 ASCII characters.
+
+ This macro returns a 16-bit value built from the two ASCII characters specified
+ by A and B.
+
+ @param A The first ASCII character.
+ @param B The second ASCII character.
+
+ @return A 16-bit value built from the two ASCII characters specified by A and B.
+
+**/
+#define SIGNATURE_16(A, B) ((A) | (B << 8))
+
+/**
+ Returns a 32-bit signature built from 4 ASCII characters.
+
+ This macro returns a 32-bit value built from the four ASCII characters specified
+ by A, B, C, and D.
+
+ @param A The first ASCII character.
+ @param B The second ASCII character.
+ @param C The third ASCII character.
+ @param D The fourth ASCII character.
+
+ @return A 32-bit value built from the two ASCII characters specified by A, B,
+ C and D.
+
+**/
+#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
+
+#define ASSERT_UNICODE_BUFFER(Buffer) ASSERT ((((UINTN) (Buffer)) & 0x01) == 0)
+
+/**
+ Returns an argument of a specified type from a variable argument list and updates
+ the pointer to the variable argument list to point to the next argument.
+
+ This function returns an argument of the type specified by TYPE from the beginning
+ of the variable argument list specified by Marker. Marker is then updated to point
+ to the next argument in the variable argument list. The method for computing the
+ pointer to the next argument in the argument list is CPU specific following the EFIAPI ABI.
+
+ @param Marker The pointer to the beginning of a variable argument list.
+ @param TYPE The type of argument to retrieve from the beginning
+ of the variable argument list.
+
+ @return An argument of the type specified by TYPE.
+
+**/
+#define BASE_ARG(Marker, TYPE) (*(TYPE *) ((Marker += _BASE_INT_SIZE_OF (TYPE)) - _BASE_INT_SIZE_OF (TYPE)))
+
+///
+/// Define the maximum number of characters that are required to
+/// encode with a NULL terminator a decimal, hexadecimal, GUID,
+/// or TIME value.
+///
+/// Maximum Length Decimal String = 28
+/// "-9,223,372,036,854,775,808"
+/// Maximum Length Hexadecimal String = 17
+/// "FFFFFFFFFFFFFFFF"
+/// Maximum Length GUID = 37
+/// "00000000-0000-0000-0000-000000000000"
+/// Maximum Length TIME = 18
+/// "12/12/2006 12:12"
+///
+#define MAXIMUM_VALUE_CHARACTERS 38
+
+///
+/// Pointer to the start of a variable argument list stored in a memory buffer. Same as UINT8 *.
+///
+typedef UINTN *BASE_LIST;
+
+/**
+ Returns the size of a data type in sizeof(UINTN) units rounded up to the nearest UINTN boundary.
+
+ @param TYPE The date type to determine the size of.
+
+ @return The size of TYPE in sizeof (UINTN) units rounded up to the nearest UINTN boundary.
+**/
+#define _BASE_INT_SIZE_OF(TYPE) ((sizeof (TYPE) + sizeof (UINTN) - 1) / sizeof (UINTN))
+
+//
+// Print primitives
+//
+#define PREFIX_SIGN BIT1
+#define PREFIX_BLANK BIT2
+#define LONG_TYPE BIT4
+#define OUTPUT_UNICODE BIT6
+#define FORMAT_UNICODE BIT8
+#define PAD_TO_WIDTH BIT9
+#define ARGUMENT_UNICODE BIT10
+#define PRECISION BIT11
+#define ARGUMENT_REVERSED BIT12
+#define COUNT_ONLY_NO_PRINT BIT13
+
+///
+/// Flags bitmask values use in UnicodeValueToString() and
+/// AsciiValueToString()
+///
+#define LEFT_JUSTIFY 0x01
+#define COMMA_TYPE 0x08
+#define PREFIX_ZERO 0x20
+#define RADIX_HEX 0x80
+
+//
+// Record date and time information
+//
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Pad1;
+ UINT32 Nanosecond;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINT8 Pad2;
+} TIME;
+
+
+/**
+ Copies one Null-terminated Unicode string to another Null-terminated Unicode
+ string and returns the new Unicode string.
+
+ This function copies the contents of the Unicode string Source to the Unicode
+ string Destination, and returns Destination. If Source and Destination
+ overlap, then the results are undefined.
+
+ If Destination is NULL, then return NULL.
+ If Destination is not aligned on a 16-bit boundary, then return NULL.
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCpy (
+ OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ );
+
+/**
+ Returns the length of a Null-terminated Unicode string.
+
+ This function returns the number of Unicode characters in the Null-terminated
+ Unicode string specified by String.
+
+ If String is NULL, then return 0.
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The length of String.
+
+**/
+UINTN
+FceStrLen (
+ IN CONST CHAR16 *String
+ );
+
+/**
+ Returns the size of a Null-terminated Unicode string in bytes, including the
+ Null terminator.
+
+ This function returns the size, in bytes, of the Null-terminated Unicode string
+ specified by String.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @return The size of String.
+
+**/
+UINTN
+FceStrSize (
+ IN CONST CHAR16 *String
+ );
+
+/**
+ Compares two Null-terminated Unicode strings, and returns the difference
+ between the first mismatched Unicode characters.
+
+ This function compares the Null-terminated Unicode string FirstString to the
+ Null-terminated Unicode string SecondString. If FirstString is identical to
+ SecondString, then 0 is returned. Otherwise, the value returned is the first
+ mismatched Unicode character in SecondString subtracted from the first
+ mismatched Unicode character in FirstString.
+
+ @param FirstString A pointer to a Null-terminated Unicode string.
+ @param SecondString A pointer to a Null-terminated Unicode string.
+
+ @retval 0 FirstString is identical to SecondString.
+ @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+FceStrCmp (
+ IN CONST CHAR16 *FirstString,
+ IN CONST CHAR16 *SecondString
+ );
+
+/**
+ Concatenates one Null-terminated Unicode string to another Null-terminated
+ Unicode string, and returns the concatenated Unicode string.
+
+ This function concatenates two Null-terminated Unicode strings. The contents
+ of Null-terminated Unicode string Source are concatenated to the end of
+ Null-terminated Unicode string Destination. The Null-terminated concatenated
+ Unicode String is returned. If Source and Destination overlap, then the
+ results are undefined.
+
+ If Destination is NULL, then ASSERT().
+ If Destination is not aligned on a 16-bit boundary, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+ than PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+ and Source results in a Unicode string with more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the
+ Null-terminator, then ASSERT().
+
+ @param Destination A pointer to a Null-terminated Unicode string.
+ @param Source A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+
+**/
+CHAR16 *
+StrCat (
+ IN OUT CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ );
+
+/**
+ Returns the first occurrence of a Null-terminated Unicode sub-string
+ in a Null-terminated Unicode string.
+
+ This function scans the contents of the Null-terminated Unicode string
+ specified by String and returns the first occurrence of SearchString.
+ If SearchString is not found in String, then NULL is returned. If
+ the length of SearchString is zero, then String is
+ returned.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+ If SearchString is NULL, then ASSERT().
+ If SearchString is not aligned on a 16-bit boundary, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and SearchString
+ or String contains more than PcdMaximumUnicodeStringLength Unicode
+ characters, not including the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+ @param SearchString A pointer to a Null-terminated Unicode string to search for.
+
+ @retval NULL If the SearchString does not appear in String.
+ @return others If there is a match.
+
+**/
+CHAR16 *
+StrStr (
+ IN CONST CHAR16 *String,
+ IN CONST CHAR16 *SearchString
+ );
+
+/**
+ Convert a Null-terminated Unicode decimal string to a value of
+ type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a decimal number. The format
+ of the input Unicode string String is:
+
+ [spaces] [decimal digits].
+
+ The valid decimal digit character is in the range [0-9]. The
+ function will ignore the pad space, which includes spaces or
+ tab characters, before [decimal digits]. The running zero in the
+ beginning of [decimal digits] will be ignored. Then, the function
+ stops at the first character that is a not a valid decimal character
+ or a Null-terminator, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then 0 is returned.
+ If String has no pad spaces or valid decimal digits,
+ then 0 is returned.
+ If the number represented by String overflows according
+ to the range defined by UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains
+ more than PcdMaximumUnicodeStringLength Unicode characters, not including
+ the Null-terminator, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrDecimalToUint64 (
+ IN CONST CHAR16 *String
+ );
+
+
+/**
+ Convert one Null-terminated ASCII string to a Null-terminated
+ Unicode string and returns the Unicode string.
+
+ This function converts the contents of the ASCII string Source to the Unicode
+ string Destination, and returns Destination. The function terminates the
+ Unicode string Destination by appending a Null-terminator character at the end.
+ The caller is responsible to make sure Destination points to a buffer with size
+ equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
+
+ @param Source A pointer to a Null-terminated ASCII string.
+ @param Destination A pointer to a Null-terminated Unicode string.
+
+ @return Destination.
+ @return NULL If Destination or Source is NULL, return NULL.
+
+**/
+CHAR16 *
+AsciiStrToUnicodeStr (
+ IN CONST CHAR8 *Source,
+ OUT CHAR16 *Destination
+ );
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and variable argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine
+
+ @param StartOfBuffer The character buffer to print the results of the parsing
+ of Format into.
+ @param BufferSize The maximum number of characters to put into buffer.
+ Zero means no limit.
+ @param Flags Initial flags value.
+ Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+ @param FormatString A Null-terminated format string.
+ @param ... The variable argument list.
+
+ @return The number of characters printed.
+
+**/
+UINTN
+BasePrintLibSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+UnicodeSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ );
+
+/**
+ Convert a Null-terminated Unicode string to a Null-terminated
+ ASCII string and returns the ASCII string.
+
+ This function converts the content of the Unicode string Source
+ to the ASCII string Destination by copying the lower 8 bits of
+ each Unicode character. It returns Destination. The function terminates
+ the ASCII string Destination by appending a Null-terminator character
+ at the end. The caller is responsible to make sure Destination points
+ to a buffer with size equal or greater than (FceStrLen (Source) + 1) in bytes.
+
+ If Destination is NULL, then ASSERT().
+ If Source is NULL, then ASSERT().
+ If Source is not aligned on a 16-bit boundary, then ASSERT().
+ If Source and Destination overlap, then ASSERT().
+
+ If any Unicode characters in Source contain non-zero value in
+ the upper 8 bits, then ASSERT().
+
+ @param Source Pointer to a Null-terminated Unicode string.
+ @param Destination Pointer to a Null-terminated ASCII string.
+
+ @reture Destination
+
+**/
+CHAR8 *
+UnicodeStrToAsciiStr (
+ IN CONST CHAR16 *Source,
+ OUT CHAR8 *Destination
+ );
+
+/**
+ Allocate new memory and then copy the Unicode string Source to Destination.
+
+ @param Dest Location to copy string
+ @param Src String to copy
+
+**/
+VOID
+NewStringCpy (
+ IN OUT CHAR16 **Dest,
+ IN CHAR16 *Src
+ );
+
+/**
+ Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a hexadecimal number.
+ The format of the input Unicode string String is
+
+ [spaces][zeros][x][hexadecimal digits].
+
+ The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+ The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+ If "x" appears in the input string, it must be prefixed with at least one 0.
+ The function will ignore the pad space, which includes spaces or tab characters,
+ before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+ [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+ first valid hexadecimal digit. Then, the function stops at the first character that is
+ a not a valid hexadecimal character or NULL, whichever one comes first.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned in a 16-bit boundary, then ASSERT().
+ If String has only pad spaces, then zero is returned.
+ If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+ then zero is returned.
+ If the number represented by String overflows according to the range defined by
+ UINT64, then ASSERT().
+
+ If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+ PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+ then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+
+ @retval Value translated from String.
+
+**/
+UINT64
+FceStrHexToUint64 (
+ IN CONST CHAR16 *String
+ );
+
+
+CHAR16
+ToUpper (
+ CHAR16 a
+ );
+
+CHAR16
+ToLower (
+ CHAR16 a
+ );
+
+/**
+ Performs a case-insensitive comparison between a Null-terminated
+ Unicode pattern string and a Null-terminated Unicode string.
+
+ @param String - A pointer to a Null-terminated Unicode string.
+ @param Pattern - A pointer to a Null-terminated Unicode pattern string.
+
+
+ @retval TRUE - Pattern was found in String.
+ @retval FALSE - Pattern was not found in String.
+
+**/
+BOOLEAN
+MetaiMatch (
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ );
+
+/**
+ Multiplies a 64-bit unsigned integer by a 32-bit unsigned integer and
+ generates a 64-bit unsigned result.
+
+ This function multiplies the 64-bit unsigned value Multiplicand by the 32-bit
+ unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+ bit unsigned result is returned.
+
+ @param Multiplicand A 64-bit unsigned value.
+ @param Multiplier A 32-bit unsigned value.
+
+ @return Multiplicand * Multiplier.
+
+**/
+UINT64
+MultU64x32 (
+ IN UINT64 Multiplicand,
+ IN UINT32 Multiplier
+ );
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. This
+ function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32 (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor
+ );
+
+/**
+ Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
+ with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the left by Count bits. The
+ low Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift left.
+ @param Count The number of bits to shift left.
+
+ @return Operand << Count.
+
+**/
+UINT64
+LShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ );
+
+/**
+ Shifts a 64-bit integer right between 0 and 63 bits. This high bits are
+ filled with zeros. The shifted value is returned.
+
+ This function shifts the 64-bit value Operand to the right by Count bits. The
+ high Count bits are set to zero. The shifted value is returned.
+
+ If Count is greater than 63, then ASSERT().
+
+ @param Operand The 64-bit operand to shift right.
+ @param Count The number of bits to shift right.
+
+ @return Operand >> Count.
+
+**/
+UINT64
+RShiftU64 (
+ IN UINT64 Operand,
+ IN UINTN Count
+ );
+
+
+/**
+ Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+ a 64-bit unsigned result and an optional 32-bit unsigned remainder.
+
+ This function divides the 64-bit unsigned value Dividend by the 32-bit
+ unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+ is not NULL, then the 32-bit unsigned remainder is returned in Remainder.
+ This function returns the 64-bit unsigned quotient.
+
+ If Divisor is 0, then ASSERT().
+
+ @param Dividend A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+ @param Remainder A pointer to a 32-bit unsigned value. This parameter is
+ optional and may be NULL.
+
+ @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32Remainder (
+ IN UINT64 Dividend,
+ IN UINT32 Divisor,
+ OUT UINT32 *Remainder
+ );
+
+/**
+ Copies a buffer to an allocated buffer.
+
+ Allocates the number bytes specified by AllocationSize, copies allocationSize bytes
+ from Buffer to the newly allocated buffer, and returns a pointer to the allocated
+ buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+FceAllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ );
+
+/**
+ Initializes the head node of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Initializes the forward and backward links of a new linked list. After
+ initializing a linked list with this function, the other linked list
+ functions may be used to add and remove nodes from the linked list. It is up
+ to the caller of this function to allocate the memory for ListHead.
+
+ If ListHead is NULL, then ASSERT().
+
+ @param ListHead A pointer to the head node of a new doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InitializeListHead (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Adds a node to the beginning of a doubly-linked list, and returns the pointer
+ to the head node of the doubly-linked list.
+
+ Adds the node Entry at the beginning of the doubly-linked list denoted by
+ ListHead, and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be inserted at the beginning
+ of a doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertHeadList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ );
+
+/**
+ Adds a node to the end of a doubly-linked list, and returns the pointer to
+ the head node of the doubly-linked list.
+
+ Adds the node Entry to the end of the doubly-linked list denoted by ListHead,
+ and returns ListHead.
+
+ If ListHead is NULL, then ASSERT().
+ If Entry is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+ of nodes in ListHead, including the ListHead node, is greater than or
+ equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+ @param Entry A pointer to a node that is to be added at the end of the
+ doubly-linked list.
+
+ @return ListHead
+
+**/
+LIST_ENTRY *
+InsertTailList (
+ IN OUT LIST_ENTRY *ListHead,
+ IN OUT LIST_ENTRY *Entry
+ );
+
+/**
+ Retrieves the first node of a doubly-linked list.
+
+ Returns the first node of a doubly-linked list. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+ If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+
+ @return The first node of a doubly-linked list.
+ @retval NULL The list is empty.
+
+**/
+LIST_ENTRY *
+GetFirstNode (
+ IN CONST LIST_ENTRY *List
+ );
+
+/**
+ Retrieves the next node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that follows Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the next node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetNextNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Retrieves the previous node of a doubly-linked list.
+
+ Returns the node of a doubly-linked list that precedes Node.
+ List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+ or InitializeListHead(). If List is empty, then List is returned.
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and List contains more than
+ PcdMaximumLinkedListLenth nodes, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @return A pointer to the previous node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetPreviousNode (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Checks to see if a doubly-linked list is empty or not.
+
+ Checks to see if the doubly-linked list is empty. If the linked list contains
+ zero nodes, this function returns TRUE. Otherwise, it returns FALSE.
+
+ If ListHead is NULL, then ASSERT().
+ If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+
+ @param ListHead A pointer to the head node of a doubly-linked list.
+
+ @retval TRUE The linked list is empty.
+ @retval FALSE The linked list is not empty.
+
+**/
+BOOLEAN
+IsListEmpty (
+ IN CONST LIST_ENTRY *ListHead
+ );
+
+/**
+ Determines if a node in a doubly-linked list is the head node of a the same
+ doubly-linked list. This function is typically used to terminate a loop that
+ traverses all the nodes in a doubly-linked list starting with the head node.
+
+ Returns TRUE if Node is equal to List. Returns FALSE if Node is one of the
+ nodes in the doubly-linked list specified by List. List must have been
+ initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),
+ then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List and Node is not
+ equal to List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the head of the doubly-linked list pointed by List.
+ @retval FALSE Node is not the head of the doubly-linked list pointed by List.
+
+**/
+BOOLEAN
+IsNull (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Determines if a node the last node in a doubly-linked list.
+
+ Returns TRUE if Node is the last node in the doubly-linked list specified by
+ List. Otherwise, FALSE is returned. List must have been initialized with
+ INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+ If List is NULL, then ASSERT().
+ If Node is NULL, then ASSERT().
+ If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+ InitializeListHead(), then ASSERT().
+ If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+ in List, including the List node, is greater than or equal to
+ PcdMaximumLinkedListLength, then ASSERT().
+ If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+ @param List A pointer to the head node of a doubly-linked list.
+ @param Node A pointer to a node in the doubly-linked list.
+
+ @retval TRUE Node is the last node in the linked list.
+ @retval FALSE Node is not the last node in the linked list.
+
+**/
+BOOLEAN
+IsNodeAtEnd (
+ IN CONST LIST_ENTRY *List,
+ IN CONST LIST_ENTRY *Node
+ );
+
+/**
+ Removes a node from a doubly-linked list, and returns the node that follows
+ the removed node.
+
+ Removes the node Entry from a doubly-linked list. It is up to the caller of
+ this function to release the memory used by this node if that is required. On
+ exit, the node following Entry in the doubly-linked list is returned. If
+ Entry is the only node in the linked list, then the head node of the linked
+ list is returned.
+
+ If Entry is NULL, then ASSERT().
+ If Entry is the head node of an empty list, then ASSERT().
+ If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+ linked list containing Entry, including the Entry node, is greater than
+ or equal to PcdMaximumLinkedListLength, then ASSERT().
+
+ @param Entry A pointer to a node in a linked list.
+
+ @return Entry.
+
+**/
+LIST_ENTRY *
+RemoveEntryList (
+ IN CONST LIST_ENTRY *Entry
+ );
+
+#endif
diff --git a/Platform/Intel/Tools/FCE/Expression.c b/Platform/Intel/Tools/FCE/Expression.c
new file mode 100644
index 0000000000..34b310d97f
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Expression.c
@@ -0,0 +1,2367 @@
+/** @file
+
+ Utility functions for expression evaluation.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IfrParse.h"
+
+#define gEmptyString L""
+//
+// Global stack used to evaluate boolean expresions
+//
+EFI_HII_VALUE *mOpCodeScopeStack = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
+
+EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
+UINTN mExpressionEvaluationStackOffset = 0;
+
+EFI_HII_VALUE *mCurrentExpressionStack = NULL;
+EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
+EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
+
+EFI_HII_VALUE *mMapExpressionListStack = NULL;
+EFI_HII_VALUE *mMapExpressionListEnd = NULL;
+EFI_HII_VALUE *mMapExpressionListPointer = NULL;
+
+/**
+ Get Value for given Name from a NameValue Storage.
+
+ @param Storage The NameValue Storage.
+ @param Name The Name.
+ @param Value The retured Value.
+
+ @retval EFI_SUCCESS Value found for given Name.
+ @retval EFI_NOT_FOUND No such Name found in NameValue storage.
+
+**/
+EFI_STATUS
+GetValueByName (
+ IN FORMSET_STORAGE *Storage,
+ IN CHAR16 *Name,
+ IN OUT CHAR16 **Value
+ )
+{
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *Node;
+
+ *Value = NULL;
+
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ while (!IsNull (&Storage->NameValueListHead, Link)) {
+ Node = NAME_VALUE_NODE_FROM_LINK (Link);
+
+ if (FceStrCmp (Name, Node->Name) == 0) {
+ NewStringCpy (Value, Node->EditValue);
+ return EFI_SUCCESS;
+ }
+
+ Link = GetNextNode (&Storage->NameValueListHead, Link);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Grow size of the stack.
+
+ This is an internal function.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+
+ @retval EFI_SUCCESS Grow stack success.
+ @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
+
+**/
+EFI_STATUS
+GrowStack (
+ IN OUT EFI_HII_VALUE **Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ IN OUT EFI_HII_VALUE **StackEnd
+ )
+{
+ UINTN Size;
+ EFI_HII_VALUE *NewStack;
+
+ Size = EXPRESSION_STACK_SIZE_INCREMENT;
+ if (*StackPtr != NULL) {
+ Size = Size + (*StackEnd - *Stack);
+ }
+
+ NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
+ if (NewStack == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (*StackPtr != NULL) {
+ //
+ // Copy from Old Stack to the New Stack
+ //
+ CopyMem (
+ NewStack,
+ *Stack,
+ (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
+ );
+
+ //
+ // Free The Old Stack
+ //
+ FreePool (*Stack);
+ }
+
+ //
+ // Make the Stack pointer point to the old data in the new stack
+ //
+ *StackPtr = NewStack + (*StackPtr - *Stack);
+ *Stack = NewStack;
+ *StackEnd = NewStack + Size;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Push an element onto the Boolean Stack.
+
+ @param Stack On input: old stack; On output: new stack
+ @param StackPtr On input: old stack pointer; On output: new stack
+ pointer
+ @param StackEnd On input: old stack end; On output: new stack end
+ @param Data Data to push.
+
+ @retval EFI_SUCCESS Push stack success.
+
+**/
+EFI_STATUS
+PushStack (
+ IN OUT EFI_HII_VALUE **Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ IN OUT EFI_HII_VALUE **StackEnd,
+ IN EFI_HII_VALUE *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for a stack overflow condition
+ //
+ if (*StackPtr >= *StackEnd) {
+ //
+ // Grow the stack
+ //
+ Status = GrowStack (Stack, StackPtr, StackEnd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Push the item onto the stack
+ //
+ CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
+ *StackPtr = *StackPtr + 1;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Pop an element from the stack.
+
+ @param Stack On input: old stack
+ @param StackPtr On input: old stack pointer; On output: new stack pointer
+ @param Data Data to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopStack (
+ IN EFI_HII_VALUE *Stack,
+ IN OUT EFI_HII_VALUE **StackPtr,
+ OUT EFI_HII_VALUE *Data
+ )
+{
+ //
+ // Check for a stack underflow condition
+ //
+ if (*StackPtr == Stack) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Pop the item off the stack
+ //
+ *StackPtr = *StackPtr - 1;
+ CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+ VOID
+ )
+{
+ mCurrentExpressionPointer = mCurrentExpressionStack;
+}
+
+
+/**
+ Push current expression onto the Stack
+
+ @param Pointer Pointer to current expression.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+ IN VOID *Pointer
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+ return PushStack (
+ &mCurrentExpressionStack,
+ &mCurrentExpressionPointer,
+ &mCurrentExpressionEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop current expression from the Stack
+
+ @param Pointer Pointer to current expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mCurrentExpressionStack,
+ &mCurrentExpressionPointer,
+ &Data
+ );
+
+ *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+ return Status;
+}
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+ VOID
+ )
+{
+ mMapExpressionListPointer = mMapExpressionListStack;
+}
+
+
+/**
+ Push the list of map expression onto the Stack
+
+ @param Pointer Pointer to the list of map expression to be pushed.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+ IN VOID *Pointer
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+ return PushStack (
+ &mMapExpressionListStack,
+ &mMapExpressionListPointer,
+ &mMapExpressionListEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop the list of map expression from the Stack
+
+ @param Pointer Pointer to the list of map expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mMapExpressionListStack,
+ &mMapExpressionListPointer,
+ &Data
+ );
+
+ *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+ return Status;
+}
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+ VOID
+ )
+{
+ mOpCodeScopeStackPointer = mOpCodeScopeStack;
+}
+
+
+/**
+ Push an Operand onto the Stack
+
+ @param Operand Operand to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushScope (
+ IN UINT8 Operand
+ )
+{
+ EFI_HII_VALUE Data;
+
+ Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Data.Value.u8 = Operand;
+
+ return PushStack (
+ &mOpCodeScopeStack,
+ &mOpCodeScopeStackPointer,
+ &mOpCodeScopeStackEnd,
+ &Data
+ );
+}
+
+
+/**
+ Pop an Operand from the Stack
+
+ @param Operand Operand to pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PopScope (
+ OUT UINT8 *Operand
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Data;
+
+ Status = PopStack (
+ mOpCodeScopeStack,
+ &mOpCodeScopeStackPointer,
+ &Data
+ );
+
+ *Operand = Data.Value.u8;
+
+ return Status;
+}
+
+
+/**
+ Push an Expression value onto the Stack
+
+ @param Value Expression value to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushExpression (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ return PushStack (
+ &mExpressionEvaluationStack,
+ &mExpressionEvaluationStackPointer,
+ &mExpressionEvaluationStackEnd,
+ Value
+ );
+}
+
+
+/**
+ Pop an Expression value from the stack.
+
+ @param Value Expression value to pop.
+
+ @retval EFI_SUCCESS The value was popped onto the stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopExpression (
+ OUT EFI_HII_VALUE *Value
+ )
+{
+ return PopStack (
+ mExpressionEvaluationStack + mExpressionEvaluationStackOffset,
+ &mExpressionEvaluationStackPointer,
+ Value
+ );
+}
+
+/**
+ Get current stack offset from stack start.
+
+ @return Stack offset to stack start.
+**/
+UINTN
+SaveExpressionEvaluationStackOffset (
+ )
+{
+ UINTN TempStackOffset;
+ TempStackOffset = mExpressionEvaluationStackOffset;
+ mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;
+ return TempStackOffset;
+}
+
+/**
+ Restore stack offset based on input stack offset
+
+ @param StackOffset Offset to stack start.
+
+**/
+VOID
+RestoreExpressionEvaluationStackOffset (
+ UINTN StackOffset
+ )
+{
+ mExpressionEvaluationStackOffset = StackOffset;
+}
+
+
+/**
+ Search a Question in Form scope using its QuestionId.
+
+ @param Form The form which contains this Question.
+ @param QuestionId Id of this Question.
+
+ @retval Pointer The Question.
+ @retval NULL Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion2 (
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 QuestionId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ if (QuestionId == 0) {
+ //
+ // The value of zero is reserved
+ //
+ return NULL;
+ }
+
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+ if (Question->QuestionId == QuestionId) {
+ return Question;
+ }
+
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Search a Question in Formset scope using its QuestionId.
+
+ @param FormSet The formset which contains this form.
+ @param Form The form which contains this Question.
+ @param QuestionId Id of this Question.
+
+ @retval Pointer The Question.
+ @retval NULL Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 QuestionId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_STATEMENT *Question;
+
+ //
+ // Search in the form scope first
+ //
+ Question = IdToQuestion2 (Form, QuestionId);
+ if (Question != NULL) {
+ return Question;
+ }
+
+ //
+ // Search in the formset scope
+ //
+ Link = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, Link)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+ Question = IdToQuestion2 (Form, QuestionId);
+ if (Question != NULL) {
+ return Question;
+ }
+
+ Link = GetNextNode (&FormSet->FormListHead, Link);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Get Expression given its RuleId.
+
+ @param Form The form which contains this Expression.
+ @param RuleId Id of this Expression.
+
+ @retval Pointer The Expression.
+ @retval NULL Specified Expression not found in the form.
+
+**/
+FORM_EXPRESSION *
+RuleIdToExpression (
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT8 RuleId
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ while (!IsNull (&Form->ExpressionListHead, Link)) {
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+
+ if ((Expression->Type == EFI_HII_EXPRESSION_RULE) && (Expression->RuleId == RuleId)) {
+ return Expression;
+ }
+
+ Link = GetNextNode (&Form->ExpressionListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Convert the input Unicode character to upper.
+
+ @param String Th Unicode character to be converted.
+
+**/
+VOID
+IfrStrToUpper (
+ IN CHAR16 *String
+ )
+{
+ while (*String != 0) {
+ if ((*String >= 'a') && (*String <= 'z')) {
+ *String = (UINT16) ((*String) & ((UINT16) ~0x20));
+ }
+ String++;
+ }
+}
+
+/**
+ Evaluate opcode EFI_IFR_TO_STRING.
+
+ @param FormSet Formset which contains this opcode.
+ @param Format String format in EFI_IFR_TO_STRING.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToString (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Format,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *PrintFormat;
+ CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS];
+ UINTN BufferSize;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (Value.Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
+ switch (Format) {
+ case EFI_IFR_STRING_UNSIGNED_DEC:
+ case EFI_IFR_STRING_SIGNED_DEC:
+ PrintFormat = L"%ld";
+ break;
+
+ case EFI_IFR_STRING_LOWERCASE_HEX:
+ PrintFormat = L"%lx";
+ break;
+
+ case EFI_IFR_STRING_UPPERCASE_HEX:
+ PrintFormat = L"%lX";
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
+ break;
+
+ case EFI_IFR_TYPE_STRING:
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+ return EFI_SUCCESS;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (String, FormSet->HiiHandle);
+ return EFI_SUCCESS;
+}
+
+/**
+ Evaluate opcode EFI_IFR_TO_UINT.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToUint (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String;
+ CHAR16 *StringPtr;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Value.Type >= EFI_IFR_TYPE_OTHER) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+ if (Value.Type == EFI_IFR_TYPE_STRING) {
+ String = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ IfrStrToUpper (String);
+ StringPtr = StrStr (String, L"0X");
+ if (StringPtr != NULL) {
+ //
+ // Hex string
+ //
+ Result->Value.u64 = FceStrHexToUint64 (String);
+ } else {
+ //
+ // decimal string
+ //
+ Result->Value.u64 = FceStrDecimalToUint64 (String);
+ }
+ FreePool (String);
+ } else {
+ CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_CATENATE.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrCatenate (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Index;
+ CHAR16 *StringPtr;
+ UINTN Size;
+
+ //
+ // String[0] - The second string
+ // String[1] - The first string
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ StringPtr = NULL;
+ Status = EFI_SUCCESS;
+
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Size = FceStrSize (String[0]);
+ StringPtr= AllocatePool (FceStrSize (String[1]) + Size);
+ ASSERT (StringPtr != NULL);
+ StrCpy (StringPtr, String[1]);
+ StrCat (StringPtr, String[0]);
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+ if (StringPtr != NULL) {
+ FreePool (StringPtr);
+ }
+
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_MATCH.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMatch (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Index;
+
+ //
+ // String[0] - The string to search
+ // String[1] - pattern
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String [Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_BOOLEAN;
+ Result->Value.b = MetaiMatch (String[0], String[1]);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_FIND.
+
+ @param FormSet Formset which contains this opcode.
+ @param Format Case sensitive or insensitive.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrFind (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Format,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Base;
+ CHAR16 *StringPtr;
+ UINTN Index;
+
+ if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Base = (UINTN) Value.Value.u64;
+
+ //
+ // String[0] - sub-string
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
+ //
+ // Case insensitive, convert both string to upper case
+ //
+ IfrStrToUpper (String[Index]);
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ if (Base >= FceStrLen (String[1])) {
+ Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
+ } else {
+ StringPtr = StrStr (String[1] + Base, String[0]);
+ Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
+ }
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_MID.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMid (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String;
+ UINTN Base;
+ UINTN Length;
+ CHAR16 *SubString;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Length = (UINTN) Value.Value.u64;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Base = (UINTN) Value.Value.u64;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ return EFI_UNSUPPORTED;
+ }
+ String = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((Length == 0) || (Base >= FceStrLen (String))) {
+ SubString = gEmptyString;
+ } else {
+ SubString = String + Base;
+ if ((Base + Length) < FceStrLen (String)) {
+ SubString[Length] = L'\0';
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+ FreePool (String);
+
+ return Status;
+}
+
+/**
+ Evaluate opcode EFI_IFR_TOKEN.
+
+ @param FormSet Formset which contains this opcode.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToken (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ UINTN Count;
+ CHAR16 *Delimiter;
+ CHAR16 *SubString;
+ CHAR16 *StringPtr;
+ UINTN Index;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Count = (UINTN) Value.Value.u64;
+
+ //
+ // String[0] - Delimiter
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String[Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ Delimiter = String[0];
+ SubString = String[1];
+ while (Count > 0) {
+ SubString = StrStr (SubString, Delimiter);
+ if (SubString != NULL) {
+ //
+ // Skip over the delimiter
+ //
+ SubString = SubString + FceStrLen (Delimiter);
+ } else {
+ break;
+ }
+ Count--;
+ }
+
+ if (SubString == NULL) {
+ //
+ // nth delimited sub-string not found, push an empty string
+ //
+ SubString = gEmptyString;
+ } else {
+ //
+ // Put a NULL terminator for nth delimited sub-string
+ //
+ StringPtr = StrStr (SubString, Delimiter);
+ if (StringPtr != NULL) {
+ *StringPtr = L'\0';
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_STRING;
+ //Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Evaluate opcode EFI_IFR_SPAN.
+
+ @param FormSet Formset which contains this opcode.
+ @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
+ @param Result Evaluation result for this opcode.
+
+ @retval EFI_SUCCESS Opcode evaluation success.
+ @retval Other Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrSpan (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN UINT8 Flags,
+ OUT EFI_HII_VALUE *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_VALUE Value;
+ CHAR16 *String[2];
+ CHAR16 *Charset;
+ UINTN Base;
+ UINTN Index;
+ CHAR16 *StringPtr;
+ BOOLEAN Found;
+
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+ return EFI_UNSUPPORTED;
+ }
+ Base = (UINTN) Value.Value.u64;
+
+ //
+ // String[0] - Charset
+ // String[1] - The string to search
+ //
+ String[0] = NULL;
+ String[1] = NULL;
+ for (Index = 0; Index < 2; Index++) {
+ Status = PopExpression (&Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value.Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+ if (String [Index] == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ }
+
+ if (Base >= FceStrLen (String[1])) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Found = FALSE;
+ StringPtr = String[1] + Base;
+ Charset = String[0];
+ while (*StringPtr != 0 && !Found) {
+ Index = 0;
+ while (Charset[Index] != 0) {
+ if ((*StringPtr >= Charset[Index]) && (*StringPtr <= Charset[Index + 1])) {
+ if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
+ Found = TRUE;
+ break;
+ }
+ } else {
+ if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
+ Found = TRUE;
+ break;
+ }
+ }
+ //
+ // Skip characters pair representing low-end of a range and high-end of a range
+ //
+ Index += 2;
+ }
+
+ if (!Found) {
+ StringPtr++;
+ }
+ }
+
+ Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Result->Value.u64 = StringPtr - String[1];
+
+Done:
+ if (String[0] != NULL) {
+ FreePool (String[0]);
+ }
+ if (String[1] != NULL) {
+ FreePool (String[1]);
+ }
+
+ return Status;
+}
+
+
+/**
+ Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+ @param Value HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+ IN EFI_HII_VALUE *Value
+ )
+{
+ UINT64 Temp;
+
+ Temp = 0;
+ switch (Value->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Temp = Value->Value.u8;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Temp = Value->Value.u16;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Temp = Value->Value.u32;
+ break;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ Temp = Value->Value.b;
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ Temp = Value->Value.u32 & 0xffffff;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ Temp = Value->Value.u32;
+ break;
+
+ default:
+ return;
+ }
+
+ Value->Value.u64 = Temp;
+}
+
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+ @param FormSet The pointer to the Formset.
+
+ @retval EFI_INVALID_PARAMETER Could not perform compare on two values.
+ @retval 0 Two operators equal.
+ @return Positive value if Value1 is greater than Value2.
+ @retval Negative value if Value1 is less than Value2.
+
+**/
+INTN
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ INTN Result;
+ INT64 Temp64;
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+
+ if ((Value1->Type >= EFI_IFR_TYPE_OTHER) || (Value2->Type >= EFI_IFR_TYPE_OTHER) ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Value1->Type == EFI_IFR_TYPE_STRING) || (Value2->Type == EFI_IFR_TYPE_STRING) ) {
+ if (Value1->Type != Value2->Type) {
+ //
+ // Both Operator should be type of String
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) {
+ //
+ // StringId 0 is reserved
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Value1->Value.string == Value2->Value.string) {
+ return 0;
+ }
+
+ Str1 = GetToken (Value1->Value.string, FormSet->UnicodeBinary);
+ if (Str1 == NULL) {
+ //
+ // String not found
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Str2 = GetToken (Value2->Value.string, FormSet->UnicodeBinary);
+ if (Str2 == NULL) {
+ FreePool (Str1);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Result = FceStrCmp (Str1, Str2);
+
+ FreePool (Str1);
+ FreePool (Str2);
+
+ return Result;
+ }
+
+ //
+ // Take remain types(integer, boolean, date/time) as integer
+ //
+ Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
+ if (Temp64 > 0) {
+ Result = 1;
+ } else if (Temp64 < 0) {
+ Result = -1;
+ } else {
+ Result = 0;
+ }
+
+ return Result;
+}
+
+/**
+ Tell whether this Operand is an constant Expression or not
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Expression OpCode.
+ @retval FALSE Not an Expression OpCode.
+
+**/
+BOOLEAN
+IsConstantExpressionOpCode (
+ IN UINT8 Operand
+ )
+{
+ if ((Operand == EFI_IFR_EQ_ID_VAL_OP) ||
+ (Operand == EFI_IFR_EQ_ID_ID_OP) ||
+ (Operand == EFI_IFR_EQ_ID_VAL_LIST_OP )||
+ (Operand == EFI_IFR_QUESTION_REF1_OP) ||
+ (Operand == EFI_IFR_QUESTION_REF2_OP) ||
+ (Operand == EFI_IFR_QUESTION_REF3_OP) ||
+ (Operand == EFI_IFR_THIS_OP ) ||
+ (Operand == EFI_IFR_SECURITY_OP) ||
+ (Operand == EFI_IFR_GET_OP) ||
+ (Operand == EFI_IFR_SET_OP)
+ ) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Update the HiiValue of question from its variable.
+
+ @param FormSet FormSet associated with this expression.
+ @param Question The pointer to the Question
+
+ @return EFI_SUCCESS
+ @return EFI_NOT_FOUND
+**/
+EFI_STATUS
+UpdateHiiValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+ EFI_HII_VALUE *HiiValue;
+
+ Status = EFI_SUCCESS;
+ HiiValue = &Question->HiiValue;
+
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ if (Question->QuestionReferToBitField) {
+ GetBitsQuestionValue (Question, VarBuffer, &HiiValue->Value.u32);
+ } else {
+ CopyMem (&HiiValue->Value.u64, VarBuffer, Question->StorageWidth);
+ }
+ return Status;
+}
+/**
+ Evaluate the result of a HII expression.
+
+ If Expression is NULL, then ASSERT.
+
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+ @param Expression Expression to be evaluated.
+ @param ConstantExpression The pointer to the flag of constant expression. If constant, will return TRUE.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
+ could not be found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_EXPRESSION *Expression,
+ IN OUT BOOLEAN *ConstantExpression
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EXPRESSION_OPCODE *OpCode;
+ FORM_BROWSER_STATEMENT *Question;
+ FORM_BROWSER_STATEMENT *Question2;
+ UINT16 Index;
+ EFI_HII_VALUE Data1;
+ EFI_HII_VALUE Data2;
+ EFI_HII_VALUE Data3;
+ FORM_EXPRESSION *RuleExpression;
+ EFI_HII_VALUE *Value;
+ INTN Result;
+ CHAR16 *StrPtr;
+ UINT32 TempValue;
+ LIST_ENTRY *SubExpressionLink;
+ FORM_EXPRESSION *SubExpression;
+ UINTN StackOffset;
+ UINTN TempLength;
+ CHAR16 TempStr[5];
+ UINT8 DigitUint8;
+ UINT8 *TempBuffer;
+
+ //
+ // Save current stack offset.
+ //
+ StackOffset = SaveExpressionEvaluationStackOffset ();
+
+ ASSERT (Expression != NULL);
+ Expression->Result.Type = EFI_IFR_TYPE_OTHER;
+
+ Link = GetFirstNode (&Expression->OpCodeListHead);
+ while (!IsNull (&Expression->OpCodeListHead, Link)) {
+ OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+
+ Link = GetNextNode (&Expression->OpCodeListHead, Link);
+
+ ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
+ ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
+ ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
+
+ Value = &Data3;
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Status = EFI_SUCCESS;
+
+ //
+ // Check whether it is a constant expression or not
+ //
+ if (*ConstantExpression) {
+ *ConstantExpression = IsConstantExpressionOpCode (OpCode->Operand);
+ }
+
+ switch (OpCode->Operand) {
+ //
+ // Built-in functions
+ //
+ case EFI_IFR_EQ_ID_VAL_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, FormSet);
+ if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_EQ_ID_ID_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
+ if (Question2 == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ UpdateHiiValue (FormSet, Question2);
+ Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet);
+ if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_EQ_ID_VAL_LIST_OP:
+
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ Value->Value.b = FALSE;
+ for (Index =0; Index < OpCode->ListLength; Index++) {
+ if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
+ Value->Value.b = TRUE;
+ break;
+ }
+ }
+ break;
+
+ case EFI_IFR_DUP_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PushExpression (Value);
+ break;
+
+ case EFI_IFR_QUESTION_REF1_OP:
+ case EFI_IFR_THIS_OP:
+ Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ UpdateHiiValue (FormSet, Question);
+ Value = &Question->HiiValue;
+ break;
+
+ case EFI_IFR_SECURITY_OP:
+ //
+ // Do nothing, as no need for static scaning
+ //
+ break;
+
+ case EFI_IFR_GET_OP:
+ //
+ // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
+ //
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Value->Value.u8 = 0;
+ if (OpCode->VarStorage != NULL) {
+ switch (OpCode->VarStorage->Type) {
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // Get value from Buffer
+ //
+ Value->Type = OpCode->ValueType;
+ CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // Get value from Buffer
+ //
+ if (OpCode->VarStorage->NewEfiVarstore) {
+ Value->Type = OpCode->ValueType;
+ CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
+ } else {
+ CopyMem (&Value->Value, OpCode->VarStorage->Buffer, OpCode->ValueWidth);
+ }
+
+
+ break;
+ case EFI_HII_VARSTORE_NAME_VALUE:
+ if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
+ //
+ // Get value from string except for STRING value.
+ //
+ Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (StrPtr != NULL);
+ TempLength = FceStrLen (StrPtr);
+ if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
+ Value->Type = OpCode->ValueType;
+ TempBuffer = (UINT8 *) &Value->Value;
+ ZeroMem (TempStr, sizeof (TempStr));
+ for (Index = 0; Index < TempLength; Index ++) {
+ TempStr[0] = StrPtr[TempLength - Index - 1];
+ DigitUint8 = (UINT8) FceStrHexToUint64 (TempStr);
+ if ((Index & 1) == 0) {
+ TempBuffer [Index/2] = DigitUint8;
+ } else {
+ TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
+ }
+ }
+ }
+ free (StrPtr);
+ StrPtr = NULL;
+ }
+ }
+ break;
+ default:
+ //
+ // Not recognize storage.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ }
+
+ break;
+
+ case EFI_IFR_QUESTION_REF3_OP:
+ if (OpCode->DevicePath == 0) {
+ //
+ // EFI_IFR_QUESTION_REF3
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // push the questions' value on to the expression stack
+ //
+ Value = &Question->HiiValue;
+ } else {
+ //
+ // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
+ // since it is impractical to evaluate the value of a Question in another
+ // Hii Package list.
+ //
+ ZeroMem (Value, sizeof (EFI_HII_VALUE));
+ }
+ break;
+
+ case EFI_IFR_RULE_REF_OP:
+ //
+ // Find expression for this rule
+ //
+ RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
+ if (RuleExpression == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Evaluate this rule expression
+ //
+ Status = EvaluateExpression (FormSet, Form, RuleExpression, ConstantExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Value = &RuleExpression->Result;
+ break;
+
+ case EFI_IFR_STRING_REF1_OP:
+ Value->Type = EFI_IFR_TYPE_STRING;
+ Value->Value.string = OpCode->Value.Value.string;
+ break;
+
+ //
+ // Constant
+ //
+ case EFI_IFR_TRUE_OP:
+ case EFI_IFR_FALSE_OP:
+ case EFI_IFR_ONE_OP:
+ case EFI_IFR_ONES_OP:
+ case EFI_IFR_UINT8_OP:
+ case EFI_IFR_UINT16_OP:
+ case EFI_IFR_UINT32_OP:
+ case EFI_IFR_UINT64_OP:
+ case EFI_IFR_UNDEFINED_OP:
+ case EFI_IFR_VERSION_OP:
+ case EFI_IFR_ZERO_OP:
+ Value = &OpCode->Value;
+ break;
+
+ //
+ // unary-op
+ //
+ case EFI_IFR_LENGTH_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = FceStrLen (StrPtr);
+ FreePool (StrPtr);
+ break;
+
+ case EFI_IFR_NOT_OP:
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ Value->Value.b = (BOOLEAN) (!Value->Value.b);
+ break;
+
+ case EFI_IFR_QUESTION_REF2_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+ if (Question == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Value = &Question->HiiValue;
+ break;
+
+ case EFI_IFR_STRING_REF2_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Validate the expression value
+ //
+ if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_STRING;
+ StrPtr = GetToken (Value->Value.u16, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ //
+ // If String not exit, push an empty string
+ //
+ //Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
+ } else {
+ Index = (UINT16) Value->Value.u64;
+ Value->Value.string = Index;
+ FreePool (StrPtr);
+ }
+ break;
+
+ case EFI_IFR_TO_BOOLEAN_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Convert an expression to a Boolean
+ //
+ if (Value->Type <= EFI_IFR_TYPE_DATE) {
+ //
+ // When converting from an unsigned integer, zero will be converted to
+ // FALSE and any other value will be converted to TRUE.
+ //
+ Value->Value.b = (BOOLEAN) (Value->Value.u64 != 0);
+
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ } else if (Value->Type == EFI_IFR_TYPE_STRING) {
+ //
+ // When converting from a string, if case-insensitive compare
+ // with "true" is True, then push True. If a case-insensitive compare
+ // with "false" is True, then push False. Otherwise, push Undefined.
+ //
+ StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ IfrStrToUpper (StrPtr);
+ if (FceStrCmp (StrPtr, L"TRUE") == 0){
+ Value->Value.b = TRUE;
+ } else if (FceStrCmp (StrPtr, L"FALSE") == 0) {
+ Value->Value.b = FALSE;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ FreePool (StrPtr);
+ goto Done;
+ }
+ FreePool (StrPtr);
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ }
+ break;
+
+ case EFI_IFR_TO_STRING_OP:
+ //Status = IfrToString (FormSet, OpCode->Format, Value);
+ break;
+
+ case EFI_IFR_TO_UINT_OP:
+ Status = IfrToUint (FormSet, Value);
+ break;
+
+ case EFI_IFR_TO_LOWER_OP:
+ case EFI_IFR_TO_UPPER_OP:
+
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Value->Type != EFI_IFR_TYPE_STRING) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+ if (StrPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ //
+ // Do nothing here, as these two Opcode are to change or update the String Package
+ //
+ FreePool (StrPtr);
+ break;
+
+ case EFI_IFR_BITWISE_NOT_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Value->Type > EFI_IFR_TYPE_DATE) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = ~Value->Value.u64;
+ break;
+
+ case EFI_IFR_SET_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Data1.Type = EFI_IFR_TYPE_BOOLEAN;
+ Data1.Value.b = FALSE;
+ //
+ // Not support SetOpcode for static scaning
+ //
+ if (OpCode->VarStorage != NULL) {
+ switch (OpCode->VarStorage->Type) {
+
+ case EFI_IFR_VARSTORE_OP:
+ CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
+ Data1.Value.b = TRUE;
+ break;
+ case EFI_IFR_VARSTORE_EFI_OP:
+ if (OpCode->VarStorage->NewEfiVarstore) {
+ CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
+ Data1.Value.b = TRUE;
+ } else {
+ CopyMem (OpCode->VarStorage->Buffer, &Value->Value, OpCode->ValueWidth);
+ Data1.Value.b = TRUE;
+ }
+ break;
+ case EFI_HII_VARSTORE_NAME_VALUE:
+
+ break;
+ break;
+ default:
+ //
+ // Not recognize storage.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ break;
+ }
+ Value = &Data1;
+ }
+ break;
+
+ //
+ // binary-op
+ //
+ case EFI_IFR_ADD_OP:
+ case EFI_IFR_SUBTRACT_OP:
+ case EFI_IFR_MULTIPLY_OP:
+ case EFI_IFR_DIVIDE_OP:
+ case EFI_IFR_MODULO_OP:
+ case EFI_IFR_BITWISE_AND_OP:
+ case EFI_IFR_BITWISE_OR_OP:
+ case EFI_IFR_SHIFT_LEFT_OP:
+ case EFI_IFR_SHIFT_RIGHT_OP:
+ //
+ // Pop an expression from the expression stack
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data2.Type > EFI_IFR_TYPE_DATE) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data1.Type > EFI_IFR_TYPE_DATE) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+
+ switch (OpCode->Operand) {
+ case EFI_IFR_ADD_OP:
+ Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
+ break;
+
+ case EFI_IFR_SUBTRACT_OP:
+ Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
+ break;
+
+ case EFI_IFR_MULTIPLY_OP:
+ Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
+ break;
+
+ case EFI_IFR_DIVIDE_OP:
+ Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
+ break;
+
+ case EFI_IFR_MODULO_OP:
+ DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);
+ Value->Value.u64 = TempValue;
+ break;
+
+ case EFI_IFR_BITWISE_AND_OP:
+ Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
+ break;
+
+ case EFI_IFR_BITWISE_OR_OP:
+ Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
+ break;
+
+ case EFI_IFR_SHIFT_LEFT_OP:
+ Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
+ break;
+
+ case EFI_IFR_SHIFT_RIGHT_OP:
+ Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_IFR_AND_OP:
+ case EFI_IFR_OR_OP:
+ //
+ // Two Boolean operator
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (OpCode->Operand == EFI_IFR_AND_OP) {
+ Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
+ } else {
+ Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
+ }
+ break;
+
+ case EFI_IFR_EQUAL_OP:
+ case EFI_IFR_NOT_EQUAL_OP:
+ case EFI_IFR_GREATER_EQUAL_OP:
+ case EFI_IFR_GREATER_THAN_OP:
+ case EFI_IFR_LESS_EQUAL_OP:
+ case EFI_IFR_LESS_THAN_OP:
+ //
+ // Compare two integer, string, boolean or date/time
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if ((Data2.Type > EFI_IFR_TYPE_BOOLEAN) && (Data2.Type != EFI_IFR_TYPE_STRING)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Pop another expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Result = CompareHiiValue (&Data1, &Data2, FormSet);
+ if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ switch (OpCode->Operand) {
+ case EFI_IFR_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_NOT_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_GREATER_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_GREATER_THAN_OP:
+ Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_LESS_EQUAL_OP:
+ Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
+ break;
+
+ case EFI_IFR_LESS_THAN_OP:
+ Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EFI_IFR_MATCH_OP:
+ Status = IfrMatch (FormSet, Value);
+ break;
+
+ case EFI_IFR_CATENATE_OP:
+ Status = IfrCatenate (FormSet, Value);
+ break;
+
+ //
+ // ternary-op
+ //
+ case EFI_IFR_CONDITIONAL_OP:
+ //
+ // Pop third expression from the expression stack
+ //
+ Status = PopExpression (&Data3);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop second expression from the expression stack
+ //
+ Status = PopExpression (&Data2);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Pop first expression from the expression stack
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Data1.Value.b) {
+ Value = &Data3;
+ } else {
+ Value = &Data2;
+ }
+ break;
+
+ case EFI_IFR_FIND_OP:
+ Status = IfrFind (FormSet, OpCode->Format, Value);
+ break;
+
+ case EFI_IFR_MID_OP:
+ Status = IfrMid (FormSet, Value);
+ break;
+
+ case EFI_IFR_TOKEN_OP:
+ Status = IfrToken (FormSet, Value);
+ break;
+
+ case EFI_IFR_SPAN_OP:
+ Status = IfrSpan (FormSet, OpCode->Flags, Value);
+ break;
+
+ case EFI_IFR_MAP_OP:
+ //
+ // Pop the check value
+ //
+ Status = PopExpression (&Data1);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check MapExpression list is valid.
+ //
+ if (OpCode->MapExpressionList.ForwardLink == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Go through map expression list.
+ //
+ SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+ while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ //
+ // Evaluate the first expression in this pair.
+ //
+ Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Compare the expression value with current value
+ //
+ if (CompareHiiValue (&Data1, &SubExpression->Result, FormSet) == 0) {
+ //
+ // Try get the map value.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Value = &SubExpression->Result;
+ break;
+ }
+ //
+ // Skip the second expression on this pair.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Goto the first expression on next pair.
+ //
+ SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+ }
+
+ //
+ // No map value is found.
+ //
+ if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ Value->Value.u8 = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PushExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Pop the final result from expression stack
+ //
+ Value = &Data1;
+ Status = PopExpression (Value);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // After evaluating an expression, there should be only one value left on the expression stack
+ //
+ if (PopExpression (Value) != EFI_ACCESS_DENIED) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Done:
+ RestoreExpressionEvaluationStackOffset (StackOffset);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
+ }
+
+ return Status;
+}
diff --git a/Platform/Intel/Tools/FCE/Fce.c b/Platform/Intel/Tools/FCE/Fce.c
new file mode 100644
index 0000000000..1845c508b5
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Fce.c
@@ -0,0 +1,6449 @@
+/** @file
+
+ FCE is a tool which enables developers to retrieve and change HII configuration ("Setup")
+ data in Firmware Device files (".fd" files).
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+
+#ifndef __GNUC__
+#define COPY_STR "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR "del \"%s\" > NUL"
+#else
+#define COPY_STR "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR "rm -r \"%s\" > /dev/null"
+#define DEL_STR "rm \"%s\" > /dev/null"
+#endif
+
+//
+// Utility global variables
+//
+OPERATION_TYPE Operations;
+
+CHAR8 mInputFdName[MAX_FILENAME_LEN];
+CHAR8 mOutputFdName[MAX_FILENAME_LEN];
+CHAR8 mOutTxtName[MAX_FILENAME_LEN];
+CHAR8 mSetupTxtName[MAX_FILENAME_LEN];
+
+CHAR8* mUtilityFilename = NULL;
+UINT32 mEfiVariableAddr = 0;
+
+UQI_PARAM_LIST *mUqiList = NULL;
+UQI_PARAM_LIST *mLastUqiList = NULL;
+LIST_ENTRY mVarListEntry;
+LIST_ENTRY mBfvVarListEntry;
+LIST_ENTRY mAllVarListEntry;
+LIST_ENTRY mFormSetListEntry;
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+
+CHAR8* mGuidToolDefinition = "GuidToolDefinitionConf.ini";
+
+//
+//gFfsArray is used to store all the FFS informations of Fd
+//
+G_EFI_FD_INFO gEfiFdInfo;
+//
+//mMultiPlatformParam is used to store the structures about multi-platform support
+//
+MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+
+UINT32 mFormSetOrderRead;
+UINT32 mFormSetOrderParse;
+
+CHAR8 mFullGuidToolDefinitionDir[_MAX_PATH];
+
+CHAR8 *mFvNameGuidString = NULL;
+
+/**
+ Check the revision of BfmLib. If not matched, return an error.
+
+ @retval EFI_SUCCESS If revision matched, return EFI_SUCCESS.
+ @retval EFI_UNSUPPORTED Other cases.
+**/
+static
+EFI_STATUS
+CheckBfmLibRevision (
+ VOID
+ )
+{
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ CHAR8 *TempSystemCommand;
+ CHAR8 *Revision;
+ FILE *FileHandle;
+ CHAR8 RevisionStr[_MAX_BUILD_VERSION];
+ UINT32 Len;
+
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ TempSystemCommand = NULL;
+ Revision = "Revision.txt";
+
+ memset (RevisionStr, 0, _MAX_BUILD_VERSION);
+
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "BfmLib -v > %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (Revision) + 1
+ );
+ if (SystemCommand == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -v > %s",
+ Revision
+ );
+
+ if (mFullGuidToolDefinitionDir[0] != 0) {
+ TempSystemCommand = SystemCommand;
+ SystemCommand = malloc (
+ strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (SystemCommandFormatString) + strlen (Revision) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ free (TempSystemCommand);
+ return EFI_UNSUPPORTED;
+ }
+ strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+ strcat (SystemCommand, OS_SEP_STR);
+ strcat (SystemCommand, TempSystemCommand);
+ free (TempSystemCommand);
+ }
+
+ system (SystemCommand);
+ free (SystemCommand);
+ FileHandle = fopen (Revision, "r");
+ if (FileHandle == NULL) {
+ printf ("Error. Read the revision file of BfmLib failed.\n");
+ return EFI_ABORTED;
+ }
+ fgets(RevisionStr, _MAX_BUILD_VERSION, FileHandle);
+ Len = strlen(RevisionStr);
+ if (RevisionStr[Len - 1] == '\n') {
+ RevisionStr[Len - 1] = 0;
+ }
+ fclose (FileHandle);
+ remove (Revision);
+
+ if (strlen (RevisionStr) > _MAX_BUILD_VERSION - 1) {
+ printf ("The revision string is too long");
+ return EFI_UNSUPPORTED;
+ }
+ if (strcmp (RevisionStr, __BUILD_VERSION) == 0) {
+ return EFI_SUCCESS;
+ }
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Transfer the Ascii string to the Dec Number
+
+ @param InStr The Ascii string.
+
+ @retval DecNum Return the Dec number.
+**/
+static
+UINT64
+StrToDec (
+ IN CHAR8 *InStr
+ )
+{
+ UINT8 Index;
+ UINTN DecNum;
+ UINTN Temp;
+
+ Index = 0;
+ DecNum = 0;
+ Temp = 0;
+
+ if (InStr == NULL) {
+ return (UINT64)-1;
+ }
+ while (Index < strlen (InStr)) {
+
+ if ((*(InStr + Index) >= '0') && (*(InStr + Index) <= '9')) {
+ Temp = *(InStr + Index) - '0';
+ } else if ((*(InStr + Index) >= 'a') && (*(InStr + Index) <= 'f')) {
+ Temp = *(InStr + Index) - 'a' + 10;
+ } else if ((*(InStr + Index) >= 'A') && (*(InStr + Index) <= 'F')) {
+ Temp = *(InStr + Index) - 'A' + 10;
+ }
+ DecNum = DecNum + Temp * (UINTN) pow (16, strlen (InStr) - Index - 1);
+ Index++;
+ }
+ return DecNum;
+}
+/**
+ Check whether there are some errors in uqi parameters of One_of
+
+ @param Question The pointer to the question Node.
+ @param UqiValue The value of One_of.
+
+ @retval TRUE If existed error, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+static
+BOOLEAN
+CheckOneOfParamError (
+ IN CONST FORM_BROWSER_STATEMENT *Question,
+ IN UINT64 UqiValue
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ UINT64 Value;
+
+ Link = NULL;
+ Option = NULL;
+ Value = 0;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ Value = 0;
+ CopyMem (&Value, &Option->Value.Value.u64, Question->StorageWidth);
+ if (Value == UqiValue) {
+ return FALSE;
+ }
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether there are some errors in uqi parameters of Orderlist
+
+ @param HiiObjList The pointer to the Hii Object Node.
+ @param UqiValue The pointer to the Uqi parameter.
+
+ @retval TRUE If existed error, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+static
+BOOLEAN
+CheckOrderParamError (
+ IN CONST FORM_BROWSER_STATEMENT *Question,
+ IN CHAR8 *UqiValue
+ )
+{
+ UINT8 MaxNum;
+ MaxNum = UqiValue[0];
+
+ if (MaxNum != (UINT8)(Question->MaxContainers)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Writes a Unicode string
+
+ @param Package A pointer to the Unicode string.
+
+ @return NULL
+**/
+static
+VOID
+WriteUnicodeStr (
+ IN CHAR16 *pcString
+ )
+{
+ UINTN Index;
+
+ if (pcString == NULL) {
+ return;
+ }
+
+ for (Index = 0; pcString[Index] != 0; Index++) {
+ printf("%c", pcString[Index] & 0x00FF);
+ }
+}
+
+/**
+ Parse and set the quick configure information by the command line.
+
+ Read the UQI Config information from command line directly, and then compare it with the value in VarList.
+ Update the Update flag in Varlist.
+
+ @param CurUqiList The pointer to the current uqi
+ @param DefaultId The default Id.
+ @param PlatformId The platform Id.
+ @param CurQuestion The pointer to the matched question
+
+ @retval EFI_SUCCESS It was complete successfully
+ @retval EFI_UNSUPPORTED Update a read-only value
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+SetUqiParametersWithQuestion (
+ IN UQI_PARAM_LIST *CurUqiList,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN FORM_BROWSER_STATEMENT *CurQuestion
+ )
+{
+ FORMSET_STORAGE *VarList;
+ BOOLEAN IsFound;
+ UINT8 *ValueAddrOfVar;
+ UINT16 Index;
+ UINT64 QuestionValue;
+ UINT64 UqiValue;
+ EFI_STATUS Status;
+ CHAR8 *ErrorStr;
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ UINT64 CurValue;
+
+ VarList = NULL;
+ Index = 0;
+ ValueAddrOfVar = NULL;
+ QuestionValue = 0;
+ UqiValue = 0;
+ ErrorStr = NULL;
+ Status = EFI_SUCCESS;
+ FormSet = NULL;
+ FormSetLink = NULL;
+ CurValue = 0;
+
+ //
+ // Search the Variable List by VarStoreId and Offset
+ //
+ IsFound = FALSE;
+ FormSetLink = GetFirstNode (&mFormSetListEntry);
+ while (!IsNull (&mFormSetListEntry, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ Status = SearchVarStorage (
+ CurQuestion,
+ NULL,
+ CurQuestion->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **) &ValueAddrOfVar,
+ &VarList
+ );
+
+ if (!EFI_ERROR (Status)) {
+ IsFound = TRUE;
+ break;
+ }
+ FormSetLink = GetNextNode (&mFormSetListEntry, FormSetLink);
+ }
+
+ if (!IsFound) {
+ if (CurUqiList->Header.ScriptsLine == 0) {
+ printf ("Error. The question in the command line doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n");
+ } else {
+ printf ("Error. The question in the line %d of script doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n", CurUqiList->Header.ScriptsLine);
+ }
+ return EFI_ABORTED;
+ }
+
+ //
+ // Check the length of variable value
+ //
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)&QuestionValue);
+ } else {
+ switch (CurQuestion->StorageWidth) {
+
+ case sizeof (UINT8):
+ QuestionValue = *(UINT8 *)ValueAddrOfVar;
+ break;
+
+ case sizeof (UINT16):
+ QuestionValue = *(UINT16 *)ValueAddrOfVar;
+ break;
+
+ case sizeof (UINT32):
+ QuestionValue = *(UINT32 *)ValueAddrOfVar;
+ break;
+
+ case sizeof (UINT64):
+ QuestionValue = *(UINT64 *)ValueAddrOfVar;
+ break;
+
+ default:
+ //
+ // The storage width of ORDERED_LIST may not be any type above.
+ //
+ ;
+ break;
+ }
+ }
+ UqiValue = *(UINT64 *)CurUqiList->Header.Value;
+ CurUqiList->SameOrNot = TRUE;
+
+ //
+ // Check and set the checkbox value
+ //
+ if (CurQuestion->Operand == EFI_IFR_CHECKBOX_OP) {
+ if ((UqiValue != 0) && (UqiValue != 1)) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated value of CHECKBOX 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ } else {
+ if (QuestionValue != UqiValue) {
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy (
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ }
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ if (CurQuestion->Operand == EFI_IFR_STRING_OP) {
+ if ((FceStrLen((wchar_t *)CurUqiList->Header.Value) + 1) * 2 > CurQuestion->StorageWidth) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated value of STRING exceed its Size.\n");
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ } else {
+ if (memcmp((CHAR8 *)CurUqiList->Header.Value, ValueAddrOfVar, CurQuestion->StorageWidth) != 0) {
+ memcpy(
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy(
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ //
+ // Check and set the NUMERIC value
+ //
+ if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
+ if ((UqiValue < CurQuestion->Minimum) || (UqiValue > CurQuestion->Maximum)) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated value of NUMERIC 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ } else {
+ if (QuestionValue != UqiValue) {
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy (
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ }
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ //
+ // Check and set the ONE_OF value
+ //
+ if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
+ if (CheckOneOfParamError (CurQuestion, UqiValue)) {
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+ sprintf (CurUqiList->Error, "Error. The updated ONE_OF value 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ } else {
+ if (QuestionValue != UqiValue) {
+ if (CurQuestion->QuestionReferToBitField) {
+ GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+ SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+ } else {
+ memcpy (
+ CurUqiList->Header.DiffValue,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ memcpy (
+ ValueAddrOfVar,
+ CurUqiList->Header.Value,
+ CurQuestion->StorageWidth
+ );
+ }
+ CurUqiList->SameOrNot = FALSE;
+ }
+ }
+ }
+ //
+ // Check and set the ORDER_LIST value
+ //
+ if (CurQuestion->Operand == EFI_IFR_ORDERED_LIST_OP) {
+ //
+ // Synchronize the MaxContainers value
+ //
+ *CurUqiList->Header.DiffValue = (UINT8)CurQuestion->MaxContainers;
+
+ if (CheckOrderParamError (CurQuestion, (CHAR8 *)CurUqiList->Header.Value)) {
+
+ CurUqiList->ErrorOrNot = TRUE;
+ CurUqiList->SameOrNot = FALSE;
+ CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+ if (CurUqiList->Error == NULL) {
+ printf ("Fail to allocate memory!\n");
+ return EFI_ABORTED;
+ }
+ memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+
+ ErrorStr = CurUqiList->Error;
+ sprintf (ErrorStr, "Error. The updated NORDERED_LIST value ");
+ ErrorStr = ErrorStr + strlen ("Error. The updated NORDERED_LIST value ");
+
+ for (Index = 0; Index < CurQuestion->StorageWidth; Index++) {
+ sprintf (ErrorStr, "%02x ", *(CurUqiList->Header.Value + Index + 1));
+ ErrorStr +=3;
+ }
+ sprintf (ErrorStr, "is invalid.\n");
+ memcpy (
+ CurUqiList->Header.DiffValue + 1,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ } else {
+ for (Index = 0; Index < CurQuestion->StorageWidth/CurQuestion->MaxContainers; Index++) {
+ CurValue = 0;
+ memcpy (
+ &CurValue,
+ (ValueAddrOfVar + Index * CurQuestion->StorageWidth/CurQuestion->MaxContainers),
+ CurQuestion->StorageWidth/CurQuestion->MaxContainers
+ );
+ if (CurValue != *((UINT64 *)CurUqiList->Header.Value + Index + 1)) {
+ CurUqiList->SameOrNot = FALSE;
+ break;
+ }
+ }
+ if (!CurUqiList->SameOrNot) {
+ memcpy (
+ CurUqiList->Header.DiffValue + 1,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ for (Index = 0; Index < CurQuestion->MaxContainers; Index++) {
+ switch (CurQuestion->StorageWidth/CurQuestion->MaxContainers) {
+
+ case sizeof (UINT8):
+ *((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ case sizeof (UINT16):
+ *((UINT16 *)ValueAddrOfVar + Index) = *(UINT16 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ case sizeof (UINT32):
+ *((UINT32 *)ValueAddrOfVar + Index) = *(UINT32 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ case sizeof (UINT64):
+ *((UINT64 *)ValueAddrOfVar + Index) = *((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+
+ default:
+ *((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+ break;
+ }
+ }
+ //
+ // Update the vaule of ORDERED_LIST according to its size
+ //
+ CurUqiList->Header.Value = (UINT8 *)((UINT64 *)CurUqiList->Header.Value);
+ memcpy (
+ CurUqiList->Header.Value + 1,
+ ValueAddrOfVar,
+ CurQuestion->StorageWidth
+ );
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse and set the quick configure information by the command line.
+
+ Read the UQI Config information from command line directly, and then compare it with the value in VarList.
+ Update the Update flag in Varlist.
+
+ @param UqiList The pointer to the uqi list
+ @param DefaultId The default Id.
+ @param PlatformId The platform Id.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @retval EFI_UNSUPPORTED Update a read-only value
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+SetUqiParameters (
+ IN UQI_PARAM_LIST *UqiList,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ FORM_BROWSER_FORM *Form;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ LIST_ENTRY *FormSetEntryListHead;
+ UQI_PARAM_LIST *CurUqiList;
+
+ FormSet = NULL;
+ FormSetLink = NULL;
+ Form = NULL;
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ FormSetEntryListHead = &mFormSetListEntry;
+
+ FormSetLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ // Parse all forms in formset
+ //
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ continue;
+ }
+ if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ continue;
+ }
+ }
+
+ CurUqiList = UqiList;
+ while (CurUqiList != NULL) {
+ if ((PlatformId == CurUqiList->Header.PlatformId[0])
+ && (DefaultId == CurUqiList->Header.DefaultId[0])
+ && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
+ ) {
+ //
+ // Add further check to avoid a case that there are many options with a
+ // same UQI (en-Us), but always returns the first one.
+ //
+ if (!CurUqiList->ParseOrNot) {
+ CurUqiList->ParseOrNot = TRUE;
+ break;
+ }
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+ if (CurUqiList != NULL) {
+ SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, Question);
+ }
+ }
+ }
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set question value per UqiList.
+
+ @param UqiList The pointer to the uqi list
+ @param DefaultId The default Id.
+ @param PlatformId The platform Id.
+**/
+VOID
+SetUqiParametersMultiMode (
+ IN UQI_PARAM_LIST *UqiList,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ UQI_PARAM_LIST *CurUqiList;
+
+ CurUqiList = UqiList;
+ while (CurUqiList != NULL) {
+ if ((CurUqiList->ParseOrNot == FALSE)
+ && (PlatformId == CurUqiList->Header.PlatformId[0])
+ && (DefaultId == CurUqiList->Header.DefaultId[0])
+ ) {
+ CurUqiList->ParseOrNot = TRUE;
+ if (CurUqiList->Header.Question != NULL) {
+ SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, CurUqiList->Header.Question);
+ }
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+}
+
+/**
+ Find the matched question for each UQI string in UqiList
+
+**/
+EFI_STATUS
+ScanUqiFullList (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ FORM_BROWSER_FORM *Form;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ LIST_ENTRY *FormSetEntryListHead;
+ UQI_PARAM_LIST *CurUqiList;
+ UINT64 PlatformId;
+ UINT16 DefaultId;
+
+ if (UqiList == NULL) {
+ return EFI_SUCCESS;
+ }
+ FormSet = NULL;
+ FormSetLink = NULL;
+ Form = NULL;
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ FormSetEntryListHead = &mFormSetListEntry;
+
+ FormSetLink = FormSetEntryListHead->ForwardLink;
+ while (FormSetEntryListHead != FormSetLink) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ // Parse all forms in formset
+ //
+ FormLink = FormSet->FormListHead.ForwardLink;
+
+ while (&FormSet->FormListHead != FormLink) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = Form->StatementListHead.ForwardLink;
+
+ while (&Form->StatementListHead != QuestionLink) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ QuestionLink = QuestionLink->ForwardLink;
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ continue;
+ } else if (Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ continue;
+ }
+
+ CurUqiList = UqiList;
+ PlatformId = 0xFFFFFFFF;
+ DefaultId = 0xFFFF;
+ while (CurUqiList != NULL) {
+ if ((CurUqiList->Header.Question == NULL)
+ && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
+ && ((PlatformId != CurUqiList->Header.PlatformId[0]) || (DefaultId != CurUqiList->Header.DefaultId[0]))
+ ) {
+ CurUqiList->Header.Question = Question;
+ PlatformId = CurUqiList->Header.PlatformId[0];
+ DefaultId = CurUqiList->Header.DefaultId[0];
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+ }
+ }
+ FormLink = FormLink->ForwardLink;
+ }
+ FormSetLink = FormSetLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create and insert the UQI Node to the UQI parameter list.
+
+ @retval Node address If successed, return the node address.
+ @retval NULL An error occurred.
+
+**/
+static
+UQI_PARAM_LIST *
+CreateInsertUqiNode (
+ )
+{
+ UQI_PARAM_LIST *Node;
+
+ Node = (UQI_PARAM_LIST *) malloc (sizeof (UQI_PARAM_LIST));
+ if (Node == NULL) {
+ return NULL;
+ }
+ memset (Node, 0, sizeof (UQI_PARAM_LIST));
+
+ if (mUqiList == NULL) {
+ mUqiList = Node;
+ } else {
+ mLastUqiList->Next = Node;
+ }
+
+ mLastUqiList = Node;
+ return Node;
+}
+/**
+ Parse the first part of QUI string
+
+ @param **argv[] The dual array pointer to the parameters.
+ @param Number The pointer to the number of the first character of UQI.
+ @param Buffer The buffer to store the first part of UQI.
+
+ @retval EFI_SUCCESS Parse the QUI parameters successfully.
+ @retval EFI_INVALID_PARAMETER An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseFirstpartOfUqi (
+ IN CHAR8 **argv[],
+ OUT UINT32 *Number,
+ OUT UINT16 **Buffer
+ )
+{
+ UINT32 Index;
+
+ Index = 0;
+
+ *Number = (UINT32)StrToDec ((*argv)[0]);
+
+ if ((*Number <= 0) || (*Number > MAX_QUI_PARAM_LEN)) {
+ printf ("Error. Invalid UQI.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Buffer = malloc ((*Number + 1) * sizeof (CHAR16));
+ assert (*Buffer != NULL);
+ memset (*Buffer, 0, (*Number + 1) * sizeof (CHAR16));
+
+ for (Index = 0; Index < *Number; Index++) {
+ if (StrToDec ((*argv)[Index]) > 0xff) {
+ printf ("Error. Invalid UQI.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ *(*Buffer + Index) = (UINT16)StrToDec ((*argv)[Index + 1]);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse the QUI input parameters from the command line
+
+ @param argc The pointer to the number of input parameters.
+ @param **argv[] The dual array pointer to the parameters.
+
+ @retval EFI_SUCCESS Parse the QUI parameters successfully.
+ @retval EFI_INVALID_PARAMETER An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseUqiParam (
+ IN UINT32 *argc,
+ IN CHAR8 **argv[]
+ )
+{
+ UINT32 Index;
+ UQI_PARAM_LIST *UqiNode;
+ EFI_STATUS Status;
+
+ Index = 0;
+ UqiNode = NULL;
+
+ if (*argc < 4) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UqiNode = CreateInsertUqiNode ();
+ assert (UqiNode != NULL);
+
+ UqiNode->Header.DefaultId = (UINT16 *) calloc (1, sizeof (UINT16));
+ UqiNode->Header.PlatformId = (UINT64 *) calloc (1, sizeof (UINT64));
+
+ Status = ParseFirstpartOfUqi (argv, &(UqiNode->Header.HexNum), &(UqiNode->Header.Data));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *argc -= (UqiNode->Header.HexNum + 1);
+ *argv += UqiNode->Header.HexNum + 1;
+ //
+ // Parse the TYPE and value
+ //
+ if (strcmp ("ONE_OF", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = ONE_OF;
+ } else if (strcmp ("NUMERIC", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = NUMERIC;
+ } else if (strcmp ("CHECKBOX", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = CHECKBOX;
+ } else if (strcmp ("STRING", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = STRING;
+ } else if (strcmp ("ORDERED_LIST", (*argv)[0]) == 0) {
+ UqiNode->Header.Type = ORDERED_LIST;
+ } else {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ *argc -= 1;
+ *argv += 1;
+ //
+ // Get the value according to the type of questions.
+ //
+ switch (UqiNode->Header.Type) {
+
+ case ONE_OF:
+ case NUMERIC:
+ case CHECKBOX:
+ UqiNode->Header.Value = malloc (sizeof (UINT64));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (UqiNode->Header.Value, 0, sizeof (UINT64));
+
+ UqiNode->Header.DiffValue = malloc (sizeof (UINT64));
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ UqiNode->Header.DiffValue,
+ 0,
+ sizeof (UINT64)
+ );
+ *(UINT64 *)(UqiNode->Header.Value) = (UINT64)StrToDec ((*argv)[0]);
+ break;
+
+ case ORDERED_LIST:
+ UqiNode->Header.Value = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ UqiNode->Header.Value,
+ 0,
+ (UINTN)StrToDec(((*argv)[0]) + 1) * sizeof (UINT64)
+ );
+
+ UqiNode->Header.DiffValue = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ UqiNode->Header.DiffValue,
+ 0,
+ (UINTN)(StrToDec ((*argv)[0]) + 1) * sizeof (UINT64)
+ );
+
+ *UqiNode->Header.Value = (UINT8)StrToDec ((*argv)[0]);
+ for (Index = 1; Index <= StrToDec ((*argv)[0]); Index++) {
+ *((UINT64 *)UqiNode->Header.Value + Index) = StrToDec ((*argv)[Index]);
+ }
+ *argc -= (UINTN)StrToDec ((*argv)[0]);
+ *argv += (UINTN)StrToDec ((*argv)[0]);
+ break;
+
+ default:
+ break;
+ }
+
+ *argc -= 1;
+ *argv += 1;
+
+ if (*argc > 0) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Parse the input Fd file, and get the file name according to the FILETYPE.
+
+ @param FdName The Name of Fd file
+ @param FILETYPE The type of Fd file
+
+ @return EFI_SUCCESS Get the file name successfully
+ @return EFI_ABORTED An error occurred.
+**/
+static
+EFI_STATUS
+ParseInFile (
+ IN CHAR8 *FdName,
+ IN FILETYPE Type
+)
+{
+ FILE *Fptr;
+
+ Fptr = NULL;
+
+ if ((Type == INFD) && ((FdName == NULL) || (Fptr = fopen (FdName, "r")) == NULL)) {
+ if (FdName != NULL) {
+ printf ("Error: The <infd> file doesn't exist '%s'\n", FdName);
+ }
+ return EFI_ABORTED;
+ }
+ if ((Type == OUTFD) && (FdName == NULL) ) {
+ printf ("Error: The <Outfd> name is NULL.\n");
+ return EFI_ABORTED;
+ }
+ if ((Type == SETUPTXT) && (FdName == NULL) ) {
+ printf ("Error: The <script> name is NULL.\n");
+ return EFI_ABORTED;
+ }
+ if (strlen (FdName) > MAX_FILENAME_LEN - 1) {
+ printf ("Error: The <fd> name is too long.\n");
+ if (Fptr != NULL) {
+ fclose (Fptr);
+ }
+ return EFI_ABORTED;
+ }
+ //
+ // Get and copy the file name
+ //
+ if (Type == INFD) {
+ strncpy (mInputFdName, FdName, MAX_FILENAME_LEN - 1);
+ mInputFdName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Type == OUTFD) {
+ strncpy (mOutputFdName, FdName, MAX_FILENAME_LEN - 1);
+ mOutputFdName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Type == OUTTXT) {
+ strncpy (mOutTxtName, FdName, MAX_FILENAME_LEN - 1);
+ mOutTxtName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Type == SETUPTXT) {
+ strncpy (mSetupTxtName, FdName, MAX_FILENAME_LEN - 1);
+ mSetupTxtName[MAX_FILENAME_LEN - 1] = 0;
+ }
+ if (Fptr != NULL) {
+ fclose (Fptr);
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Print the usage of this tools.
+
+ @return NULL
+**/
+static
+VOID
+Usage (
+ VOID
+ )
+{
+ //
+ // Print utility header
+ //
+ printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
+ UTILITY_NAME,
+ UTILITY_MAJOR_VERSION,
+ UTILITY_MINOR_VERSION,
+ __BUILD_VERSION
+ );
+ //
+ // Copyright declaration
+ //
+ fprintf (stdout, "Copyright (c) 2010-2018, Intel Corporation. All rights reserved.\n\n");
+ //
+ // Summary usage
+ //
+ fprintf (stdout, "The tool enables you to retrieve and change HII configuration (Setup) data in \n");
+ fprintf (stdout, "Firmware Device files.\n");
+ fprintf (stdout, "\nUsage: \n");
+ fprintf (stdout, " FCE [read -i <infd> [<PlatformId UQI>] ['>' <script>]] \n");
+ fprintf (stdout, " FCE [update -i <infd> [<PlatformId UQI>|-s <script>] -o <outfd>\n");
+ fprintf (stdout, " [--remove|--ignore] [-g <FvNameGuid>]] [-a]\n");
+ fprintf (stdout, " FCE [verify -i <infd> -s <script>] \n");
+ fprintf (stdout, " FCE [updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>] \n");
+ fprintf (stdout, " FCE [[help] | [-?]] \n");
+ fprintf (stdout, "\n");
+
+ fprintf (stdout, "Options:\n");
+ fprintf (stdout, " read Extract the HII data from the <infd> file. \n");
+ fprintf (stdout, " update Update the HII data to the <outfd> file. \n");
+ fprintf (stdout, " verify Verify the current platform configuration. \n");
+ fprintf (stdout, " updateq Update the current platform configuration by command line.\n");
+ fprintf (stdout, " updateq only supports common mode.\n");
+ fprintf (stdout, " help Display the help information.\n");
+
+ fprintf (stdout, " <infd> The name of a existing Firmware Device binary file input. \n");
+ fprintf (stdout, " <PlatformId UQI> The UQI is required in multi-platform mode to represent a \n");
+ fprintf (stdout, " PlatformId question from the VFR files used during binary \n");
+ fprintf (stdout, " image creation. It must not be used for common mode. \n");
+ fprintf (stdout, " <outfd> The name of a Firmware Device binary file output. \n");
+ fprintf (stdout, " <script> The name of a configure scripts.\n");
+ fprintf (stdout, " <UQI> A hex number followed by an array of hex numbers. \n");
+ fprintf (stdout, " <Question Type> One of ORDERED_LIST, ONE_OF, NUMERIC, STRING or CHECKBOX. \n");
+ fprintf (stdout, " <Value> A single hex number, if the <Question Type> is ONE_OF,\n");
+ fprintf (stdout, " NUMERIC, or CHECKBOX. Or a single hex number containing \n");
+ fprintf (stdout, " the array size followed by an array of that length of hex\n");
+ fprintf (stdout, " numbers, if the <Question Type> is ORDERED_LIST. \n");
+ fprintf (stdout, " <FvNameGuid> GuidValue is one specific FvName guid value.\n");
+ fprintf (stdout, " Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.\n");
+ fprintf (stdout, " -i Import an existing FD file <infd>. \n");
+ fprintf (stdout, " -o Create the new FD with the changes made. \n");
+ fprintf (stdout, " -s Import config scripts. \n");
+ fprintf (stdout, " > Redirect the output to a scripts. \n");
+ fprintf (stdout, " -? Display the help information. \n");
+ fprintf (stdout, " --remove If one or more of the settings that are updated also \n");
+ fprintf (stdout, " exists in NV RAM, remove them only in multi-platform mode.\n");
+ fprintf (stdout, " --ignore If one or more of the settings that are updated also \n");
+ fprintf (stdout, " existsin NV RAM, ignore them only in multi-platform mode.\n");
+ fprintf (stdout, " -g Specify the FV image to store the multi-platform default \n");
+ fprintf (stdout, " setting. If it is missing, the multi-platform default \n");
+ fprintf (stdout, " will be inserted into BFV image.\n");
+ fprintf (stdout, " -a Specify this tool to choose the smaller size between two \n");
+ fprintf (stdout, " different storage formats in NV RAM. It's only vaild in \n");
+ fprintf (stdout, " multi-platform mode. \n");
+ fprintf (stdout, "\n");
+
+ fprintf (stdout, "Mode:\n");
+ fprintf (stdout, " Common Extract the HII data from IFR binary and update it to the \n");
+ fprintf (stdout, " EFI variable. \n");
+ fprintf (stdout, " Multi-platform The default value depends on the PlatformId and DefaultId \n");
+ fprintf (stdout, " described in the VFR files. This tool will create the \n");
+ fprintf (stdout, " binary file to store default settings at build time for \n");
+ fprintf (stdout, " different platforms and modes adding all default settings \n");
+ fprintf (stdout, " into BFV as one FFS.\n");
+
+ fprintf (stdout, "\n");
+}
+
+/**
+ Parse the command line parameters
+
+ @param argc The pointer to number of input parameters.
+ @param *argv[] The pointer to the parameters.
+
+ @retval EFI_SUCCESS Parse the parameters successfully.
+ @retval EFI_INVALID_PARAMETER An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseCommmadLine (
+ IN UINTN argc,
+ IN CHAR8 *argv[]
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT8 IndexParamI;
+ UINT8 IndexParamS;
+ UINT8 IndexParamO;
+ UINT8 IndexParamRemove;
+ UINT8 IndexParamIgnore;
+ UINT8 IndexParamOptimize;
+ EFI_GUID FvNameGuid;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+ IndexParamI = 0;
+ IndexParamO = 0;
+ IndexParamS = 0;
+ IndexParamRemove = 0;
+ IndexParamIgnore = 0;
+ IndexParamOptimize = 0;
+ mMultiPlatformParam.SizeOptimizedParam = FALSE;
+ //
+ // Check for only own one operations
+ //
+ if (argc == 0) {
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ if (
+ argc == 1 \
+ && ((stricmp(argv[0], "read") == 0) \
+ || (stricmp(argv[0], "update") == 0) \
+ || (stricmp(argv[0], "updateq") == 0) \
+ || (stricmp(argv[0], "verify") == 0) )
+ ) {
+ printf ("Error: Some parameters have been lost. Please correct. \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ while (argc > 0) {
+ if (stricmp(argv[0], "read") == 0) {
+ Operations = READ;
+ argc--;
+ argv++;
+
+ if (argc < 2) {
+ printf ("Error. The correct command is 'FCE read -i <infd>'. \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Get input FD file name.
+ //
+ if (stricmp (argv[0], "-i") == 0) {
+ Status = ParseInFile (argv[1], INFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ }
+ //
+ // Parse the QUI parameters
+ //
+ if (argc > 2) {
+ Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ break;
+
+ } else if (stricmp(argv[0], "update") == 0) {
+ //
+ // Update the config file to Fd
+ //
+ Operations = UPDATE;
+ argc--;
+ argv++;
+
+ if (argc < 4) {
+ printf ("Error. The correct command is 'FCE update -i <infd> [<PlatformId UQI>|-s <script>] -o <outfd>' \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ continue;
+ } else if (stricmp(argv[0], "verify") == 0) {
+ //
+ // 3. Parse the command line "FCE verify -i <infd> -s <script>"
+ //
+ Operations = VERIFY;
+ argc--;
+ argv++;
+
+ if (argc < 4) {
+ printf ("Error. The correct command is 'FCE verify -i <infd> -s <script>'\n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ continue;
+ } else if (stricmp(argv[0], "updateq") == 0) {
+ //
+ // Parse the command line "FCE updateq -i <infd> -o<outfd> <UQI> <Question Type> <Value>"
+ //
+ argc--;
+ argv++;
+
+ //
+ // Get input/output FD file name.
+ //
+ Index = 2;
+ while ((Index > 0) && (argc > 1)) {
+ if (stricmp (argv[0], "-i") == 0) {
+ Status = ParseInFile (argv[1], INFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ Index--;
+ IndexParamI++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-o") == 0) {
+ Status = ParseInFile (argv[1], OUTFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ Index--;
+ IndexParamO++;
+ continue;
+ }
+ if (
+ (argc >= 1) \
+ && (stricmp(argv[0], "-o") != 0) \
+ && (stricmp(argv[0], "-i") != 0)
+ ) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ if (Index != 0) {
+ printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
+ Usage ();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Parse the QUI parameters
+ //
+ Status = ParseUqiParam ((UINT32 *)&argc,&argv);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Operations = UPDATEQ;
+ break;
+ }
+
+ if (stricmp (argv[0], "-i") == 0) {
+ Status = ParseInFile (argv[1], INFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ IndexParamI++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-o") == 0) {
+ Status = ParseInFile (argv[1], OUTFD);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ IndexParamO++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-s") == 0) {
+ Status = ParseInFile (argv[1], SETUPTXT);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ argc -= 2;
+ argv += 2;
+ IndexParamS++;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-g") == 0) {
+ Status = StringToGuid (argv[1], &FvNameGuid);
+ if (EFI_ERROR (Status)) {
+ printf ("Error: Invalid parameters for -g option in command line. \n");
+ Usage();
+ goto Done;
+ }
+ mFvNameGuidString = argv[1];
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ if (stricmp (argv[0], "-a") == 0) {
+ argc -= 1;
+ argv += 1;
+ IndexParamOptimize++;
+ mMultiPlatformParam.SizeOptimizedParam = TRUE;
+ continue;
+ }
+
+ if (stricmp (argv[0], "--remove") == 0) {
+ argc -= 1;
+ argv += 1;
+ IndexParamRemove++;
+ Operations = UPDATE_REMOVE;
+ continue;
+ }
+
+ if (stricmp (argv[0], "--ignore") == 0) {
+ argc -= 1;
+ argv += 1;
+ IndexParamIgnore++;
+ Operations = UPDATE_IGNORE;
+ continue;
+ }
+
+ if ((stricmp(argv[0], "help") == 0) || (stricmp(argv[0], "-?") == 0)) {
+
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Operations should not be none
+ //
+ if ( Operations == NONE ) {
+ printf ("Error. Only support read/update/verify/updateq mode. \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Operations == UPDATE) {
+ Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
+ if (!EFI_ERROR (Status)) {
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ argc = argc - mMultiPlatformParam.Uqi.HexNum - 1;
+ argv = argv + mMultiPlatformParam.Uqi.HexNum + 1;
+ continue;
+ }
+ }
+
+ if (
+ (argc >= 1) \
+ && (stricmp(argv[0], "-?") != 0)
+ && (stricmp(argv[0], "help") != 0)
+ && (stricmp(argv[0], "verify") != 0)
+ && (stricmp(argv[0], "read") != 0)
+ && (stricmp(argv[0], "update") != 0)
+ && (stricmp(argv[0], "updateq") != 0)
+ && (stricmp(argv[0], "-o") != 0)
+ && (stricmp(argv[0], "-i") != 0)
+ && (stricmp(argv[0], "-s") != 0)
+ && (stricmp(argv[0], "-a") != 0)
+ && (stricmp(argv[0], "-g") != 0)
+ && (stricmp(argv[0], "--remove") != 0)
+ && (stricmp(argv[0], "--ignore") != 0)
+ ) {
+ printf ("Error: Invalid parameters exist in command line. \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ //
+ // Check the repeated parameters in command line, such as "-i -i"
+ //
+ if (
+ (IndexParamI > 1)
+ || (IndexParamO > 1)
+ || (IndexParamS > 1)
+ || (IndexParamOptimize > 1)
+ || (IndexParamRemove > 1)
+ || (IndexParamIgnore > 1)
+ ) {
+ printf ("Error: Redundant parameters exist in command line.\n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ //
+ // Check improper parameters in command line, such as "FCE read -i -s"
+ //
+ if (
+ ((Operations == READ) && ((IndexParamO >= 1) || (IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+ || ((Operations == VERIFY) && ((IndexParamO >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+ || ((Operations == UPDATEQ) && ((IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+ || ((Operations == UPDATE) && ((IndexParamRemove >= 1) && (IndexParamIgnore >= 1)))
+ || ((Operations != UPDATE && Operations != UPDATE_REMOVE && Operations != UPDATE_IGNORE) && ((IndexParamOptimize >= 1) || (mFvNameGuidString != NULL)))
+ ) {
+ printf ("Error: Improper parameters exist in command line. \n");
+ Usage();
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+Done:
+ return Status;
+}
+
+/**
+ Check whether exists the valid variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+static
+BOOLEAN
+ExistEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ BOOLEAN Existed;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ Existed = TRUE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Check the Monotonic based authenticate variable
+ //
+ Existed = ExistMonotonicBasedEfiVarOrNot (StorageListHead);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Check the Time Sample authenticate variable
+ //
+ Existed = ExistTimeBasedEfiVarOrNot (StorageListHead);
+ } else {
+ //
+ // Check the normal variable
+ //
+ Existed = ExistNormalEfiVarOrNot (StorageListHead);
+ }
+
+ return Existed;
+}
+
+/**
+ Exchange the data between Efi variable and the data of VarList
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+static
+EFI_STATUS
+EfiVarAndListExchange (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ EFI_STATUS Status;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ Status = EFI_ABORTED;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Update the Monotonic based authenticate variable
+ //
+ Status = SynAuthEfiVariable (VarToList, StorageListHead);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Update the Time Sample authenticate variable
+ //
+ Status = SynAuthEfiVariableBasedTime (VarToList, StorageListHead);
+ } else {
+ //
+ // Update the normal variable
+ //
+ Status = SynEfiVariable (VarToList, StorageListHead);
+ }
+
+ return Status;
+}
+
+/**
+ Check the layout of NvStorage and remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+static
+EFI_STATUS
+RemoveEfiVar (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ EFI_STATUS Status;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ Status = EFI_ABORTED;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Update the Monotonic based authenticate variable
+ //
+ Status = RemoveAuthEfiVariable (StorageListHead);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Update the Time Sample authenticate variable
+ //
+ Status = RemoveAuthEfiVariableBasedTime (StorageListHead);
+ } else {
+ //
+ // Update the normal variable
+ //
+ Status = RemoveNormalEfiVariable (StorageListHead);
+ }
+
+ return Status;
+}
+
+/**
+ Parse the all formset in one VfrBin.
+
+ Parse all questions, variables and expression in VfrBin, and store
+ it in Formset and Form.
+
+ @param BaseAddr The pointer to the array of VfrBin base address.
+ @param UniBinBaseAddress The pointer to one Uni string base address.
+
+ @retval EFI_SUCCESS The Search was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ParseFormSetInVfrBin (
+ IN UINTN **BaseAddr,
+ IN UINTN *UniBinBaseAddress,
+ IN UINT8 Index
+ )
+{
+ UINT32 PackageLength;
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *FormSet;
+ UINT8 *IfrBinaryData;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ UINT32 IfrOffset;
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+ FormSet = NULL;
+ IfrBinaryData = NULL;
+ IfrOpHdr = NULL;
+
+ //
+ // The first 4 Bytes of VfrBin is used to record the Array Length
+ // The header of VfrBin is, ARRAY LENGTH:4 Bytes, PACKAGE HEADER:4 Bytes (2 Bytes for Len, and the other for Type)
+ //
+ PackageLength = *(UINT32 *)*(BaseAddr + Index) - 4;
+ IfrBinaryData = (UINT8 *)*(BaseAddr + Index) + 4;
+
+ //
+ // Go through the form package to parse OpCode one by one.
+ //
+ IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
+
+ while (IfrOffset < PackageLength) {
+ //
+ // Search the Formset in VfrBin
+ //
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) (IfrBinaryData + IfrOffset);
+
+ if (IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) {
+ FormSet = calloc (sizeof (FORM_BROWSER_FORMSET), sizeof (CHAR8));
+ if (FormSet == NULL) {
+ return EFI_ABORTED;
+ }
+ FormSet->IfrBinaryData = IfrBinaryData + IfrOffset;
+ FormSet->UnicodeBinary = (UINT8 *) UniBinBaseAddress;
+ //
+ //This length will be corrected in ParseOpCodes function.
+ //
+ FormSet->IfrBinaryLength = PackageLength - IfrOffset;
+ //
+ // Parse opcodes in the formset IFR binary.
+ //
+ Status = ParseOpCodes (FormSet);
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (FormSet->StorageListHead);
+ DestroyFormSet (FormSet);
+ return EFI_ABORTED;
+ }
+ IfrOffset += FormSet->IfrBinaryLength;
+ FormSet->EnUsStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
+ FormSet->EnUsStringList.CachedIdNum = 0;
+ FormSet->EnUsStringList.MaxIdNum = STRING_NUMBER;
+ FormSet->UqiStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
+ FormSet->UqiStringList.CachedIdNum = 0;
+ FormSet->UqiStringList.MaxIdNum = STRING_NUMBER;
+ //
+ // Insert the FormSet to mFormSet
+ //
+ InsertTailList (&mFormSetListEntry, &FormSet->Link);
+ } else {
+ IfrOffset += IfrOpHdr->Length;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Store all defaultId to mMultiPlatformParam.
+
+ The mMultiPlatformParam.DefaultId[0] is used to store standard default.
+
+ @param DefaultId The current defaultID.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+VOID
+StoreAllDefaultId (
+ IN UINT16 DefaultId
+)
+{
+ UINT32 Index;
+
+ if ((mMultiPlatformParam.DefaultIdNum == 0) && (DefaultId != 0)) {
+ mMultiPlatformParam.DefaultId[0] = DefaultId;
+ mMultiPlatformParam.DefaultIdNum++;
+ return;
+ }
+ //
+ // Only store the different value to mMultiPlatformParam.DefaultId[1] - mMultiPlatformParam.DefaultId[n]
+ //
+ for (Index = 0; Index < mMultiPlatformParam.DefaultIdNum; Index++) {
+ if (mMultiPlatformParam.DefaultId[Index] == DefaultId) {
+ return;
+ }
+ }
+ mMultiPlatformParam.DefaultId[Index] = DefaultId;
+ mMultiPlatformParam.DefaultIdNum++;
+}
+
+/**
+ Read all defaultId and platformId from binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+**/
+VOID
+ReadDefaultAndPlatformIdFromBfv (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+)
+{
+ UINT16 Length;
+ UINT16 Size;
+ UINT32 Index;
+
+ Length = *(UINT16 *)Binary - sizeof (UINT16);
+ Index = 0;
+ Size = 0;
+
+ Binary = Binary + sizeof (UINT16);
+
+ for (Size = 0; Size < Length; Size += sizeof (UINT16) + mMultiPlatformParam.PlatformIdWidth, Index++) {
+ Storage->DefaultId[Index] = *(UINT16 *)(Binary + Size);
+ memcpy (&Storage->PlatformId[Index], (Binary + Size + sizeof (UINT16)), mMultiPlatformParam.PlatformIdWidth);
+ }
+ Storage->DefaultPlatformIdNum = Index - 1;
+}
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+UINT32
+WriteDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+)
+{
+ UINT16 Length;
+ UINT32 Index;
+ UINT8 *Buffer;
+
+ Length = 0;
+ Buffer = Binary;
+
+ Buffer = Buffer + sizeof (CHAR16);
+
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ *(UINT16 *)Buffer = Storage->DefaultId[Index];
+ Buffer = Buffer + sizeof (CHAR16);
+ memcpy (Buffer, &Storage->PlatformId[Index], mMultiPlatformParam.PlatformIdWidth);
+ Buffer = Buffer + mMultiPlatformParam.PlatformIdWidth;
+ }
+ Length = (UINT16) (Buffer - Binary);
+ //
+ // Record the offset to the first two bytes
+ //
+ *(UINT16 *)Binary = Length;
+
+ return Length;
+}
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+UINT32
+WriteNvStoreDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+)
+{
+ UINT16 Length;
+ UINT32 Index;
+ UINT8 *Buffer;
+
+ Length = 0;
+ Buffer = Binary + 8;
+
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ *(UINT64 *)Buffer = Storage->PlatformId[Index];
+ Buffer = Buffer + sizeof(UINT64);
+ *(UINT16 *)Buffer = Storage->DefaultId[Index];
+ Buffer = Buffer + sizeof(UINT16);
+ // for Resered
+ Buffer = Buffer + 6;
+ }
+ Length = (UINT16) (Buffer - Binary - 8);
+ // for Header size
+ Length += 4;
+ return Length;
+}
+
+/**
+ Read the platformId from questions.
+
+ @retval EFI_SUCCESS It was complete successfully.
+ @return EFI_ABORTED An error occurred.
+**/
+EFI_STATUS
+ReadPlaformId (
+ IN FORM_BROWSER_STATEMENT *CurQuestion
+)
+{
+ UINT16 Index;
+ UINT64 IdValue;
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ UINT64 Step;
+
+ Index = 0;
+ IdValue = 0;
+ Step = 0;
+ //
+ // Check whether it is the question of paltform Id
+ //
+ if (!CompareUqiHeader (&(CurQuestion->Uqi), &(mMultiPlatformParam.Uqi))) {
+ return EFI_ABORTED;
+ }
+ //
+ // Copy the Question with platform to mMultiPlatformParam
+ //
+ memcpy (&mMultiPlatformParam.PlatformIdQuestion, CurQuestion, sizeof (FORM_BROWSER_STATEMENT));
+ mMultiPlatformParam.Question = CurQuestion;
+ //
+ // Pick up the value of NUMERIC and ONE_OF from current question and fill it in mMultiPlatformParam
+ //
+ mMultiPlatformParam.PlatformIdWidth = CurQuestion->StorageWidth;
+
+ if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
+ Index = 0;
+ if (CurQuestion->Step == 0) {
+ Step = 1;
+ } else {
+ Step = CurQuestion->Step;
+ }
+ for (IdValue = CurQuestion->Minimum; IdValue < CurQuestion->Maximum; IdValue += Step) {
+ mMultiPlatformParam.PlatformId[Index++] = (UINT64)IdValue;
+ }
+ }
+
+ if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
+ Index = 0;
+
+ Link = GetFirstNode (&CurQuestion->OptionListHead);
+ while (!IsNull (&CurQuestion->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ mMultiPlatformParam.PlatformId[Index++] = Option->Value.Value.u64;
+ Link = GetNextNode (&CurQuestion->OptionListHead, Link);
+ }
+ }
+
+ if (Index >= MAX_PLATFORM_DEFAULT_ID_NUM) {
+ return EFI_ABORTED;
+ }
+ mMultiPlatformParam.PlatformIdNum = Index;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clear the buffer of Storage list.
+
+ @param StorageListHead The pointer to the entry of the storage list
+ @param DefaultId The default Id for multi-platform support
+ @param PlatformId The platform Id for multi-platform support
+
+ @retval NULL
+**/
+VOID
+ClearStorageEntryList (
+ IN LIST_ENTRY *StorageListHead,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+
+ Storage = NULL;
+
+ StorageLink = GetFirstNode (StorageListHead);
+
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (Storage != NULL) {
+ memset (Storage->Buffer, 0x0, Storage->Size);
+ Storage->DefaultId[0] = DefaultId;
+ Storage->PlatformId[0] = PlatformId;
+ Storage->DefaultPlatformIdNum = 0;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+}
+
+/**
+ Append the platformid and default to the variables of CurDefaultId and CurPlatformId
+
+ @param StorageListHead The pointer to the storage list
+ @param CurDefaultId The default Id for multi-platform mode
+ @param CurPlatformId The platform Id for multi-platform mode
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+
+ @retval NULL
+**/
+VOID
+AppendIdToVariables (
+ IN LIST_ENTRY *StorageListHead,
+ IN UINT16 CurDefaultId,
+ IN UINT64 CurPlatformId,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+)
+{
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+
+ Storage = NULL;
+
+ StorageLink = GetFirstNode (StorageListHead);
+
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+
+ if ((Storage->DefaultId[0] == CurDefaultId)
+ && (Storage->PlatformId[0] == CurPlatformId)
+ ) {
+ ++Storage->DefaultPlatformIdNum;
+ Storage->DefaultId[Storage->DefaultPlatformIdNum] = DefaultId;
+ Storage->PlatformId[Storage->DefaultPlatformIdNum] = PlatformId;
+ }
+
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+}
+
+
+/**
+ Check whether StorageListHead2 is included in StorageListHead1
+
+ @param StorageListHead1 The pointer to the entry of storage list
+ @param StorageListHead2 The pointer to the entry of storage list
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+
+ @retval TRUE Totally included.
+ @return FALSE Other cases.
+**/
+BOOLEAN
+ComparePartSameVariableList (
+ IN LIST_ENTRY *StorageListHead1,
+ IN LIST_ENTRY *StorageListHead2,
+ OUT UINT16 *DefaultId,
+ OUT UINT64 *PlatformId
+)
+{
+ LIST_ENTRY *StorageLink;
+ LIST_ENTRY *TempStorageHead;
+ LIST_ENTRY *TempStorageLink;
+ LIST_ENTRY *TempStorageHead2;
+ LIST_ENTRY *TempStorageLink2;
+ FORMSET_STORAGE *Storage;
+ FORMSET_STORAGE *TempStorage;
+ FORMSET_STORAGE *TempStorage2;
+ UINT16 CurDefaultId;
+ UINT64 CurPlatformId;
+ UINT32 VariableNum;
+ UINT32 Index;
+
+ StorageLink = NULL;
+ TempStorageHead = NULL;
+ TempStorageLink = NULL;
+ TempStorageHead2 = NULL;
+ TempStorageLink2 = NULL;
+ Storage = NULL;
+ TempStorage = NULL;
+ TempStorage2 = NULL;
+ CurDefaultId = 0;
+ CurPlatformId = 0;
+ VariableNum = 0;
+ Index = 0;
+ TempStorageHead = StorageListHead1;
+
+
+ //
+ // Get the number of variables in StorageListHead2;
+ //
+ StorageLink = GetFirstNode (StorageListHead2);
+
+ while (!IsNull (StorageListHead2, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // For multi-platform support, only need to calcuate the type of EFI_IFR_VARSTORE_EFI_OP.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot &&
+ (Storage->Type == EFI_IFR_VARSTORE_EFI_OP) && (Storage->Name != NULL) && (Storage->NewEfiVarstore) &&
+ ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)) {
+ VariableNum++;
+ }
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ }
+ //
+ // Parse every variables in StorageListHead1 and compare with ones in StorageListHead2
+ // Only all variables in StorageListHead2 are included in StorageListHead1, return TRUE.
+ //
+ StorageLink = GetFirstNode (StorageListHead1);
+
+ while (!IsNull (StorageListHead1, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Get specified DefaultId and PlatformId firstly
+ //
+ CurDefaultId = Storage->DefaultId[0];
+ CurPlatformId = Storage->PlatformId[0];
+ Index = 0;
+ //
+ // Compare all variables under same defaultId and platformId
+ //
+ TempStorageLink = GetFirstNode (TempStorageHead);
+ while (!IsNull (TempStorageHead, TempStorageLink)) {
+ TempStorage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
+ if ((TempStorage->DefaultId[0] == CurDefaultId)
+ && (TempStorage->PlatformId[0] == CurPlatformId)
+ && (TempStorage->Name != NULL)
+ && (TempStorage->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && (TempStorage->NewEfiVarstore)
+ && ((TempStorage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
+ ) {
+ //
+ //Search the matched variable by Guid and name in StorageListHead2
+ //
+ TempStorageHead2 = StorageListHead2;
+ TempStorageLink2 = GetFirstNode (TempStorageHead2);
+
+ while (!IsNull (TempStorageHead2, TempStorageLink2)) {
+ TempStorage2 = FORMSET_STORAGE_FROM_LINK (TempStorageLink2);
+ if ((TempStorage2->Name != NULL)
+ && (TempStorage2->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && (TempStorage2->NewEfiVarstore)
+ && ((TempStorage2->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
+ && !FceStrCmp (TempStorage->Name, TempStorage2->Name)
+ && !CompareGuid(&TempStorage->Guid, &TempStorage2->Guid)
+ ) {
+ if (CompareMem (TempStorage->Buffer, TempStorage2->Buffer, TempStorage->Size) == 0) {
+ Index++;
+ }
+ }
+ TempStorageLink2 = GetNextNode (TempStorageHead2, TempStorageLink2);
+ }
+ }
+ TempStorageLink = GetNextNode (TempStorageHead, TempStorageLink);
+ }
+ //
+ // Check the matched variable number
+ //
+ if (Index == VariableNum) {
+ *DefaultId = CurDefaultId;
+ *PlatformId = CurPlatformId;
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead1, StorageLink);
+ }
+ return FALSE;
+}
+
+/**
+ Check whether the defaultId and platformId mathched the variable or not
+
+ @param Storage The pointer to the storage
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+
+ @retval TRUE Not Matched.
+ @return FALSE Matched any one
+**/
+BOOLEAN
+NotEqualAnyIdOfStorage (
+IN FORMSET_STORAGE *Storage,
+IN UINT16 DefaultId,
+IN UINT64 PlatformId
+)
+{
+ UINT32 Index;
+
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ if ((Storage->DefaultId[Index] == DefaultId)
+ &&(Storage->PlatformId[Index] == PlatformId)
+ ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Copy Stroage from StorageListHead2 to StorageListHead1
+
+ @param NewStorageListHead The pointer to the entry of storage list
+ @param OldStorageListHead The pointer to the entry of storage list
+ @param DefaultId The default Id for multi-platform mode
+ @param PlatformId The platform Id for multi-platform mode
+ @param AssignIdOrNot If True, assign the platform Id and default Id to storage;
+ Or else, only copy the variables under the specified platform
+ Id and default to the other list.
+ @param Mode The operation of mode
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+BuildVariableList (
+ IN LIST_ENTRY *NewStorageListHead,
+ IN LIST_ENTRY *OldStorageListHead,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN BOOLEAN AssignIdOrNot,
+ IN OPERATION_TYPE Mode
+)
+{
+ LIST_ENTRY *StorageLink;
+ LIST_ENTRY *NameValueLink;
+ FORMSET_STORAGE *Storage;
+ FORMSET_STORAGE *StorageCopy;
+ IN LIST_ENTRY *StorageListHead1;
+ IN LIST_ENTRY *StorageListHead2;
+ NAME_VALUE_NODE *NameValueNode;
+ NAME_VALUE_NODE *CopyNameValueNode;
+
+ Storage = NULL;
+ NameValueNode = NULL;
+ StorageListHead1 = NewStorageListHead;
+ StorageListHead2 = OldStorageListHead;
+
+ StorageLink = GetFirstNode (StorageListHead2);
+
+ while (!IsNull (StorageListHead2, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+
+ if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
+ ||(Storage->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ //
+ // Only support EfiVarStore in Multi-Platform mode, and the attribute must be EFI_VARIABLE_NON_VOLATILE
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (Storage->Type == EFI_IFR_VARSTORE_OP) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ }
+ if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ }
+ if (AssignIdOrNot) {
+ Storage->DefaultId[0] = DefaultId;
+ Storage->PlatformId[0] = PlatformId;
+ } else {
+ //
+ //only copy the variables under the specified platform Id and default to the other list.
+ //
+ if ((Mode == VERIFY) && (NotEqualAnyIdOfStorage (Storage, DefaultId, PlatformId))) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ } else if ((Mode != VERIFY) && (Storage->DefaultId[0] != DefaultId || Storage->PlatformId[0] != PlatformId) ) {
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ continue;
+ }
+ }
+ }
+ //
+ // Copy Storage Node
+ //
+ if (Storage->Name == NULL) {
+ return EFI_ABORTED;
+ }
+ StorageCopy = NULL;
+ StorageCopy = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (StorageCopy == NULL) {
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (StorageCopy, Storage, sizeof (FORMSET_STORAGE));
+
+ if (Mode == VERIFY) {
+ StorageCopy->DefaultId[0] = DefaultId;
+ StorageCopy->PlatformId[0] = PlatformId;
+ }
+ //
+ //Set the flags for sorting out the variables
+ //
+ StorageCopy->Skip = FALSE;
+
+ StorageCopy->Name = NULL;
+ StorageCopy->Name = calloc (FceStrLen (Storage->Name) + 1, sizeof (CHAR16));
+ if (StorageCopy->Name == NULL) {
+ printf ("Memory allocation failed.\n");
+ free (StorageCopy);
+ return EFI_ABORTED;
+ }
+ StrCpy (StorageCopy->Name, Storage->Name);
+
+ StorageCopy->Buffer = NULL;
+ StorageCopy->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ if (StorageCopy->Buffer == NULL) {
+ free (StorageCopy->Name);
+ free (StorageCopy);
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ CopyMem (StorageCopy->Buffer, Storage->Buffer, Storage->Size);
+ //
+ // Copy NameValue list of storage node
+ //
+ InitializeListHead (&StorageCopy->NameValueListHead);
+
+ NameValueLink = GetFirstNode (&Storage->NameValueListHead);
+
+ while (!IsNull (&Storage->NameValueListHead, NameValueLink)) {
+
+ NameValueNode = NAME_VALUE_NODE_FROM_LINK (NameValueLink);
+ CopyNameValueNode = NULL;
+ CopyNameValueNode = calloc (sizeof (NAME_VALUE_NODE), sizeof (CHAR8));
+ if (CopyNameValueNode == NULL) {
+ free (StorageCopy->Name);
+ free (StorageCopy->Buffer);
+ free (StorageCopy);
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (CopyNameValueNode, NameValueNode, sizeof (NAME_VALUE_NODE));
+
+ CopyNameValueNode->Name = NULL;
+ CopyNameValueNode->Value = NULL;
+ CopyNameValueNode->EditValue = NULL;
+
+ CopyNameValueNode->Name = calloc (FceStrLen (NameValueNode->Name) + 1, sizeof (CHAR16));
+ CopyNameValueNode->Value = calloc (FceStrLen (NameValueNode->Value) + 1, sizeof (CHAR16));
+ CopyNameValueNode->EditValue = calloc (FceStrLen (NameValueNode->EditValue) + 1, sizeof (CHAR16));
+ if ((CopyNameValueNode->Name == NULL)
+ || (CopyNameValueNode->Value == NULL)
+ || (CopyNameValueNode->EditValue == NULL)
+ ) {
+ free (StorageCopy->Name);
+ free (StorageCopy->Buffer);
+ free (StorageCopy);
+ if (CopyNameValueNode->Name != NULL) {
+ free (CopyNameValueNode->Name );
+ }
+ if (CopyNameValueNode->Value != NULL) {
+ free (CopyNameValueNode->Value);
+ }
+ if (CopyNameValueNode->EditValue != NULL) {
+ free (CopyNameValueNode->EditValue);
+ }
+ free (CopyNameValueNode);
+ printf ("Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ StrCpy (CopyNameValueNode->Name, NameValueNode->Name);
+ StrCpy (CopyNameValueNode->Value, NameValueNode->Value);
+ StrCpy (CopyNameValueNode->EditValue, NameValueNode->EditValue);
+ //
+ // Insert it to StorageCopy->NameValueListHead
+ //
+ InsertTailList(&StorageCopy->NameValueListHead,&CopyNameValueNode->Link);
+ NameValueLink = GetNextNode (&Storage->NameValueListHead, NameValueLink);
+ }
+
+ //
+ // Insert it to StorageListHead1
+ //
+ InsertTailList(StorageListHead1,&StorageCopy->Link);
+ }
+ StorageLink = GetNextNode (StorageListHead2, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the current defaultId and platfrom is equal to the first one of one
+ group of defaultId and platformId which have the same variable data.
+
+ @param DefaultId The default Id
+ @param PlatformId The platform Id
+
+ @retval TRUE If not equal to the first defaultId and platformId, return TRUE
+ @return EFI_ABORTED Others
+**/
+BOOLEAN
+NoTheKeyIdOfGroup (
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < mMultiPlatformParam.KeyIdNum; Index++) {
+ if (
+ (DefaultId == mMultiPlatformParam.KeyDefaultId[Index])
+ && (PlatformId == mMultiPlatformParam.KeyPlatformId[Index])
+ ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Evaluate the value in all formset according to the defaultId and platformId.
+
+ If not the multi-platform mode, the defaultId is 0. In this case, the
+ platform Id will be the default value of that question.
+
+ @param UpdateMode It will be TRUE in update Mode
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+EvaluateTheValueInFormset (
+ IN BOOLEAN UpdateMode
+ )
+{
+ EFI_STATUS Status;
+ UINT16 DefaultId;
+ UINT64 PlatformId;
+ UINT16 CurDefaultId;
+ UINT64 CurPlatformId;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ UINT32 Index;
+ UQI_PARAM_LIST *CurUqiList;
+
+ Status = EFI_SUCCESS;
+
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ ScanUqiFullList (mUqiList);
+
+ //
+ // Multi-platform mode support
+ //
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
+ PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (UpdateMode && NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+ //
+ // Initialize the Storage of mVarListEntry
+ //
+ ClearStorageEntryList (&mVarListEntry, DefaultId, PlatformId);
+
+ Status = ExtractDefault (
+ NULL,
+ NULL,
+ DefaultId,
+ PlatformId,
+ SystemLevel
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Clear the platformId as 0 after calculation.
+ //
+ Status = AssignThePlatformId (0);
+ if (EFI_ERROR (Status)) {
+ printf ("Failed to clear the platformid.\n");
+ return Status;
+ }
+ //
+ // Update the value from script file
+ //
+ if (UpdateMode) {
+ SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+ }
+ //
+ // If not existed the same variables in mAllVarListEntry, insert the new ones.
+ // Or else, only add the defaultId and platformId to the former one.
+ //
+ if (ComparePartSameVariableList (&mAllVarListEntry, &mVarListEntry, &CurDefaultId, &CurPlatformId)) {
+ AppendIdToVariables (&mAllVarListEntry, CurDefaultId, CurPlatformId, DefaultId, PlatformId);
+ } else {
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // In update mode, add the other defaultId and platform of a group to the variale list
+ //
+ if (UpdateMode) {
+ CurUqiList = mUqiList;
+
+ while (CurUqiList != NULL) {
+ if ((DefaultId == CurUqiList->Header.DefaultId[0])
+ && (PlatformId == CurUqiList->Header.PlatformId[0])
+ ) {
+ break;
+ }
+ CurUqiList = CurUqiList->Next;
+ }
+
+ if (CurUqiList == NULL) {
+ return EFI_ABORTED;
+ }
+
+ for (Index = 1; Index < CurUqiList->Header.IdNum; Index++) {
+ CurDefaultId = CurUqiList->Header.DefaultId[Index];
+ CurPlatformId = CurUqiList->Header.PlatformId[Index];
+ AppendIdToVariables (&mAllVarListEntry, DefaultId, PlatformId, CurDefaultId, CurPlatformId);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ //
+ // General mode
+ //
+ Status = ExtractDefault (
+ NULL,
+ NULL,
+ 0,
+ 0,
+ SystemLevel
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // If existed the variable in NvStorage, copy them to mVarListEntry.
+ // Synchronize the default value from the EFI variable zone to variable list
+ //
+ Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
+ if (Status == EFI_INVALID_PARAMETER) {
+ Status = EFI_ABORTED;
+ return Status;
+ }
+ //
+ // Update the value from script file
+ //
+ if (UpdateMode) {
+ Status = SetUqiParameters (mUqiList,0, 0);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check and compare the value between the script file and variable from BFV.
+
+ It's used in the update operation of multi-plaform mode.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+CheckValueUpdateList (
+ VOID
+ )
+{
+ UINT16 DefaultId;
+ UINT64 PlatformId;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ EFI_STATUS Status;
+ FORMSET_STORAGE *Storage;
+ LIST_ENTRY *StorageLink;
+ UINT16 PreDefaultId;
+ UINT64 PrePlatformId;
+
+ Storage = NULL;
+ PreDefaultId = 0xFFFF;
+ PrePlatformId = 0xFFFFFFFFFFFFFFFF;
+
+ ScanUqiFullList (mUqiList);
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ StorageLink = GetFirstNode (&mBfvVarListEntry);
+ while (!IsNull (&mBfvVarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ continue;
+ } else {
+ PreDefaultId = Storage->DefaultId[0];
+ PrePlatformId = Storage->PlatformId[0];
+ }
+ DefaultId = PreDefaultId;
+ PlatformId = PrePlatformId;
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+ //
+ // Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
+ // the FormSet->StorageListHead.
+ //
+ DestroyAllStorage (&mVarListEntry);
+ Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ }
+ } else {
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
+ PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+ //
+ // Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
+ // the FormSet->StorageListHead.
+ //
+ DestroyAllStorage (&mVarListEntry);
+ Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
+
+ If not multi-platform mode, only return EFI_ABORTED.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ReadAllIfrToFromset (
+ IN VOID *Fv,
+ IN UINTN Length
+ )
+{
+ UINT8 NumberofMachingVfrBin;
+ UINTN *VfrBinBaseAddress;
+ UINTN *UniBinBaseAddress;
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_SECTION_STRUCT *EfiBufferHeader;
+ VOID *EfiAddr;
+
+ NumberofMachingVfrBin = 0;
+ VfrBinBaseAddress = NULL;
+ UniBinBaseAddress = NULL;
+ Status = EFI_SUCCESS;
+ EfiBufferHeader = NULL;
+ EfiAddr = NULL;
+
+ //
+ // Locate the efi base address
+ //
+ EfiBufferHeader = malloc (sizeof (EFI_SECTION_STRUCT));
+ if (EfiBufferHeader == NULL) {
+ return EFI_ABORTED;
+ }
+ memset (
+ EfiBufferHeader,
+ 0,
+ sizeof (EFI_SECTION_STRUCT)
+ );
+
+ Status = ParseSection (
+ TRUE,
+ (UINT8 *)Fv,
+ Length,
+ &EfiBufferHeader
+ );
+ if (Status != EFI_SUCCESS) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+ EfiAddr = (VOID *)EfiBufferHeader->BufferBase;
+ //
+ //Search the Offset at the end of FFS, whatever it is compressed or not
+ //
+ Status = SearchVfrBinInFFS (Fv, EfiAddr, Length, &VfrBinBaseAddress, &NumberofMachingVfrBin);
+ if (Status != EFI_SUCCESS) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ Status = SearchUniBinInFFS (
+ Fv,
+ EfiAddr,
+ Length,
+ &UniBinBaseAddress
+ );
+ if (Status != EFI_SUCCESS) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Read all Ifr information into Formset and Form structure
+ //
+ for (Index = 0; Index < NumberofMachingVfrBin; Index++) {
+ if ((EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *(VfrBinBaseAddress + Index)
+ || (EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *UniBinBaseAddress
+ ) {
+ printf ("Failed to locate Ifr data from efi by the offset.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ Status = ParseFormSetInVfrBin (
+ (UINTN **)VfrBinBaseAddress,
+ (UINTN *)*UniBinBaseAddress,
+ Index
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+
+Done:
+ //
+ // Free the memory which stores the offset
+ //
+ if (VfrBinBaseAddress != NULL) {
+ free (VfrBinBaseAddress);
+ }
+ if (UniBinBaseAddress != NULL) {
+ free (UniBinBaseAddress);
+ }
+ //
+ // Free the memory for uncompressed space in section
+ //
+ for (Index = 0; Index < EfiBufferHeader->UnCompressIndex; Index++) {
+ if ((VOID *)EfiBufferHeader->UncompressedBuffer[Index] != NULL) {
+ free ((VOID *)EfiBufferHeader->UncompressedBuffer[Index]);
+ }
+ }
+ return Status;
+}
+
+/**
+ Get next questions of four kinds in FormSet list.
+
+ If not one kinds of ONE_OF CHECK_BOX ORDER_LIST and NUMERIC, continue to parse next question.
+ If parse to the end of questions, return NULL.
+
+ @param FormSetEntryListHead the pointer to the LIST_ENTRY
+ @param OrderOfQuestion the order of question
+
+ @retval If succeed, return the pointer to the question
+ @return NULL
+**/
+FORM_BROWSER_STATEMENT *
+GetNextQuestion (
+ IN LIST_ENTRY *FormSetEntryListHead,
+ IN OUT UINT32 *OrderOfQuestion
+ )
+{
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ FORM_BROWSER_FORM *Form;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ UINT32 Index;
+
+ FormSet = NULL;
+ FormSetLink = NULL;
+ Form = NULL;
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ Index = 0;
+
+ FormSetLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ // Parse all forms in formset
+ //
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (*OrderOfQuestion == Index++) {
+ (*OrderOfQuestion)++;
+ return Question;
+ }
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ }
+ return NULL;
+}
+
+/**
+ Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
+
+ If not multi-platform mode, only return EFI_ABORTED.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ReadDefaultAndPlatformId (
+ IN LIST_ENTRY *FormSetEntryListHead
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormLink;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ LIST_ENTRY *DefaultStoreLink;
+ FORM_BROWSER_STATEMENT *CurQuestion;
+ UINT32 MatchedNum;
+ UINT32 QuestionOrder;
+
+ Status = EFI_SUCCESS;
+ CurQuestion = NULL;
+ MatchedNum = 0;
+ QuestionOrder = 0;
+ //
+ //Check whether it is the Multi-Platform solution or not
+ //
+ if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ //
+ // Read defaultId from FormSet List
+ //
+ FormLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
+ //
+ // Parse Default Store in formset
+ //
+ DefaultStoreLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+ while (!IsNull (&FormSet->DefaultStoreListHead, DefaultStoreLink)) {
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultStoreLink);
+ StoreAllDefaultId (DefaultStore->DefaultId);
+ DefaultStoreLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultStoreLink);
+ }
+ FormLink = GetNextNode (FormSetEntryListHead, FormLink);
+ }
+
+ //
+ //Read the platformId from FormSetList
+ //
+ while ((CurQuestion = GetNextQuestion (FormSetEntryListHead, &QuestionOrder)) != NULL) {
+ Status = ReadPlaformId (CurQuestion);
+ if (!EFI_ERROR (Status)) {
+ MatchedNum++;
+ }
+ }
+
+ if (MatchedNum == 0) {
+ printf ("There are no questions included in the platformid in the FD.");
+ Status = EFI_ABORTED;
+ } else if (MatchedNum > 1) {
+ printf ("There are %d questions included in the platformid in the FD.", MatchedNum);
+ Status = EFI_ABORTED;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+
+ return Status;
+}
+
+/**
+ Read the first two bytes to check whether it is Ascii or UCS2.
+
+ @param ScriptFile Pointer to the script file.
+
+ @reture TRUE If ascii, return TRUE
+ @reture FALSE Others, return FALSE.
+
+**/
+FILE_TYPE
+IsAsciiOrUcs2 (
+ IN FILE *ScriptFile
+ )
+{
+ CHAR16 FirstTwoBytes;
+
+ fread(&FirstTwoBytes, 1, 2, ScriptFile);
+
+ if (FirstTwoBytes == BigUnicodeFileTag) {
+ return BIG_UCS2;
+ } else if (FirstTwoBytes == LittleUnicodeFileTag) {
+ return LITTLE_UCS2;
+ } else {
+ return ASCII;
+ }
+}
+
+/**
+ Read Unicode characters and transfer it to ASCII.
+
+ @param ScriptFile The pointer to the script file.
+ @param Type The type of BigUCS2 or LittleUCS2
+
+ @return The ASCII characters
+
+**/
+CHAR8 *
+ReadUcs2ToStr (
+ IN OUT FILE *ScriptFile,
+ IN FILE_TYPE Type
+)
+{
+ CHAR16 TempChar16;
+ CHAR16 TempChar8;
+ CHAR8 *StrChar8;
+ UINTN Index;
+ BOOLEAN FirstParse;
+
+ TempChar16 = L'\0';
+ TempChar8 = '\0';
+ StrChar8 = NULL;
+ Index = 0;
+ FirstParse = TRUE;
+
+ if (ScriptFile == NULL) {
+ return NULL;
+ }
+ StrChar8 = calloc (MAX_STR_LEN_FOR_PICK_UQI, sizeof (CHAR8));
+ assert (StrChar8);
+
+ for (Index = 0; Index < MAX_STR_LEN_FOR_PICK_UQI; Index++) {
+ //
+ // The first parse should skip the 0x0020 (BigUCS2) or 0x2000 (LittleUCS2)
+ //
+ if (FirstParse) {
+ do {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ } while ((TempChar16 == 0x0020) || (TempChar16 == 0x2000));
+ FirstParse = FALSE;
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ }
+ //
+ // Read until break the "Space"
+ //
+ if ((TempChar16 == 0x0020) || (TempChar16 == 0x2000)) {
+ break;
+ }
+ if (Type == BIG_UCS2) {
+ TempChar8 = (CHAR8)TempChar16;
+ } else {
+ TempChar8 = (CHAR8)(TempChar16 >> 8);
+ }
+ memcpy (StrChar8 + Index, &TempChar8, 0x1);
+ }
+ if (Index == MAX_STR_LEN_FOR_PICK_UQI) {
+ free (StrChar8);
+ return NULL;
+ }
+ *(StrChar8 + Index) = '\0';
+
+ return StrChar8;
+}
+
+/**
+ Read Unicode characters and transfer it to ASCII.
+
+ @param AsciiStr The pointer to the Ascii string. It may inlcudes blank space.
+ @param IdArray The pointer to the array of Id.
+
+ @return The number of default or platform Id
+
+**/
+static
+UINT16
+GetNumFromAsciiString (
+ IN CHAR8 *AsciiStr,
+ IN OUT UINT64 *IdArray
+)
+{
+ UINT16 Index1;
+ UINT16 Index2;
+ UINT16 NumofId;
+ CHAR8 CharArray[16];
+ BOOLEAN ExistedValue;
+
+ Index1 = 0;
+ Index2 = 0;
+ NumofId = 0;
+ ExistedValue = FALSE;
+
+ while (*(AsciiStr + Index1) != '\n') {
+
+ Index2 = 0;
+ ExistedValue = FALSE;
+ memset (CharArray, 0, 16);
+ for (; *(AsciiStr + Index1) == ' '; Index1++);
+ for (; (*(AsciiStr + Index1) != ' ') && (*(AsciiStr + Index1) != '\n'); Index1++) {
+ assert (Index2 <= 15);
+ *(CharArray + Index2++) = *(AsciiStr + Index1);
+ ExistedValue = TRUE;
+ }
+ if (ExistedValue && (*(AsciiStr + Index1 - 1) != '\n')) {
+ sscanf(CharArray, "%lld", (long long *)&IdArray[NumofId++]);
+ }
+ }
+ return NumofId;
+}
+
+/**
+ Parse the script file to build the linked list of question structures.
+
+ Pick up the UQI information and save it to the UqiList. The current scripts
+ could be Ascii or UCS2 (Little or Big Mode).
+
+ @param ScriptFile The pointer to the script file.
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER ScriptFile is NULL
+
+**/
+static
+EFI_STATUS
+PickUpUqiFromScript (
+ IN FILE *ScriptFile
+ )
+{
+ CHAR8 TempChar;
+ BOOLEAN InQuote;
+ CHAR16 TempChar16;
+ UINT32 UqiSize;
+ CHAR16 *UqiBuffer;
+ CHAR8 Type[32];
+ UINT16 Index;
+ UQI_PARAM_LIST *UqiNode;
+ UINTN MaxContainers;
+ UINT32 ScriptsLine;
+ FILE_TYPE AsciiOrUcs2;
+ CHAR8 *Char8Str;
+ CHAR8 DefaultIdStr[30];
+ CHAR8 PlatformIdStr[30];
+ CHAR8 PlatformUqi[30];
+ UINT16 Index1;
+ UINT16 Index2;
+ UINT16 Index3;
+ UINT16 Index4;
+ UINT16 Index5;
+ BOOLEAN ReadDefaultId;
+ BOOLEAN ReadPlatformId;
+ BOOLEAN ReadPlatformIdUqi;
+ UINT64 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT64 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 DefaultIdNum;
+ UINT16 PlatformIdNum;
+ UINT8 Array[MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 IdStart;
+ UINT16 IdEnd;
+
+ Char8Str = NULL;
+ ScriptsLine = 0;
+ AsciiOrUcs2 = ASCII;
+ Index1 = 0;
+ Index2 = 0;
+ Index3 = 0;
+ Index4 = 0;
+ Index5 = 0;
+ ReadDefaultId = FALSE;
+ ReadPlatformId = FALSE;
+ ReadPlatformIdUqi = FALSE;
+ DefaultIdNum = 1;
+ PlatformIdNum = 1;
+ InQuote = FALSE;
+
+ memset (DefaultId, 0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ memset (PlatformId, 0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ memcpy (DefaultIdStr, "/ FCEKEY DEFAULT_ID:", strlen ("/ FCEKEY DEFAULT_ID:") + 1);
+ memcpy (PlatformIdStr,"/FCEKEY PLATFORM_ID:", strlen ("/FCEKEY PLATFORM_ID:") + 1);
+ memcpy (PlatformUqi, "/FCEKEY PLATFORM_UQI:", strlen ("/FCEKEY PLATFORM_UQI:") + 1);
+
+ if (ScriptFile == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check the file type
+ //
+ AsciiOrUcs2 = IsAsciiOrUcs2 (ScriptFile);
+ if (AsciiOrUcs2 == ASCII) {
+ fseek (ScriptFile, 0, SEEK_SET);
+ }
+
+ while(!feof(ScriptFile)) {
+ //
+ // Reset local data
+ //
+ TempChar = '\0';
+ TempChar16 = L'\0';
+ UqiSize = 0;
+ UqiBuffer = NULL;
+ MaxContainers = 0;
+ UqiNode = NULL;
+ memset(Type, 0, 32);
+ //
+ // Read first character of the line to find the line type
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ //
+ // Take "\n\r" one line
+ //
+ if (TempChar != 0x0d) {
+ ScriptsLine++;
+ }
+ switch (TempChar) {
+
+ case 'Q':
+ //
+ // Process question line
+ //
+ // Read size of UQI string
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %x", (INT32 *)&UqiSize);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %x", (INT32 *)&UqiSize);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (UqiSize > MAX_INPUT_ALLOCATE_SIZE) {
+ return EFI_ABORTED;
+ }
+ if (UqiSize == 0) {
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+ }
+ //
+ // Malloc buffer for string size + null termination
+ //
+ UqiBuffer = (CHAR16 *)calloc(UqiSize + 1, sizeof(CHAR16));
+
+ if (UqiBuffer == NULL) {
+ printf("Error. Unable to allocate 0x%04lx bytes for UQI string -- FAILURE\n", (unsigned long)((UqiSize + 1) * sizeof(CHAR16)));
+ break;
+ }
+ //
+ // Read UQI string
+ //
+ for (Index = 0; Index < UqiSize; Index++) {
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %hx", (short *)&(UqiBuffer[Index]));
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ free (UqiBuffer );
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %hx", (short *)&(UqiBuffer[Index]));
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ }
+ //
+ // Set null termination
+ //
+ UqiBuffer[Index] = 0;
+ //
+ // Read question type
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, "%31s", Type);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %31s", Type);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (stricmp(Type, "ONE_OF") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = ONE_OF;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf("Fail to allocate memory");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf("Fail to allocate memory");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+
+ } else if (stricmp(Type, "CHECKBOX") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = CHECKBOX;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+
+ } else if (stricmp(Type, "STRING") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+
+ UqiNode->Header.Type = STRING;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+ InQuote = FALSE;
+ IdStart = 0;
+ IdEnd = 0;
+ for (Index = 0; Index < MAX_INPUT_ALLOCATE_SIZE; Index ++) {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ if (TempChar == '\"') {
+ if (InQuote == TRUE) {
+ InQuote = FALSE;
+ IdEnd = Index;
+ } else {
+ InQuote = TRUE;
+ IdStart = Index;
+ }
+ }
+ if (Index > IdStart) {
+ if (InQuote == FALSE) {
+ break;
+ }
+ *(UqiNode->Header.Value + Index - IdStart -1) = TempChar;
+ Index ++;
+ }
+
+ }
+ if (IdEnd < IdStart) {
+ printf("The STRING is not end with \" character!\n");
+ return EFI_ABORTED;
+ }
+ if (IdStart == 0) {
+ printf("The STRING is not start with \" character!\n");
+ return EFI_ABORTED;
+ }
+
+ } else if (stricmp(Type, "NUMERIC") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = NUMERIC;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.Value = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(1, sizeof(UINT64));
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+
+ } else if (stricmp(Type, "ORDERED_LIST") == 0) {
+ UqiNode = CreateInsertUqiNode ();
+ if (UqiNode == NULL) {
+ free (UqiBuffer);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Type = ORDERED_LIST;
+ UqiNode->Header.HexNum = UqiSize;
+ UqiNode->Header.Data = UqiBuffer;
+ UqiNode->Header.IdNum = PlatformIdNum;
+ UqiNode->Header.DefaultId = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+ if (UqiNode->Header.DefaultId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+ if (UqiNode->Header.PlatformId == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+ UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+ }
+ memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %x", (INT32 *)&MaxContainers);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %x", (INT32 *)&MaxContainers);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (MaxContainers > MAX_INPUT_ALLOCATE_SIZE) {
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.Value = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
+ if (UqiNode->Header.Value == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ UqiNode->Header.DiffValue = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
+ if (UqiNode->Header.DiffValue == NULL) {
+ printf ("Fali to allocate memory!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *UqiNode->Header.Value = (UINT8) MaxContainers;
+ *UqiNode->Header.DiffValue = (UINT8) MaxContainers;
+
+ for (Index = 1; Index <= MaxContainers; Index++) {
+ if (*(UqiNode->Header.Value + Index) == '/') {
+ printf ("Error. Failed to parse the value of ORDERED_LIST.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %llx", ((long long *)UqiNode->Header.Value + Index));
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %llx", ((long long *)UqiNode->Header.Value + Index));
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ }
+
+ } else {
+ //
+ // Unknown type
+ //
+ // Free UQI buffer before skipping to next line
+ //
+ free(UqiBuffer);
+ UqiBuffer = NULL;
+ printf ("Error. Invalid parameters exist in scripts line %d", ScriptsLine);
+ return EFI_ABORTED;
+ }
+ UqiNode->Header.ScriptsLine = ScriptsLine;
+ //
+ // Skip to next line
+ //
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+
+ case '\n':
+ case '\r':
+ //
+ // Newline, skip to next character
+ //
+ break;
+
+ case '/':
+ //
+ // Get the value of PlatformId and DefaultId from comments
+ //
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ //
+ //"/ DefaultId :"
+ //
+ if (!ReadDefaultId) {
+ if (TempChar == DefaultIdStr[Index1]) {
+ Index1++;
+ } else {
+ Index1 = 0;
+ }
+ if (Index1 == strlen (DefaultIdStr)) {
+ Index1 = 0;
+ Index3 = 0;
+ memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+ ReadDefaultId = TRUE;
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ }
+ } else if (ReadDefaultId) {
+ if (TempChar == '\n') {
+ ReadDefaultId = FALSE;
+ Array[Index3] = TempChar;
+ DefaultIdNum = GetNumFromAsciiString ((CHAR8 *)Array, DefaultId);
+ mMultiPlatformParam.KeyDefaultId[mMultiPlatformParam.KeyIdNum] = (UINT16)DefaultId[0];
+ } else {
+ Array[Index3++] = TempChar;
+ }
+ }
+ //
+ //"/ PlatformId:"
+ //
+ if (!ReadPlatformId) {
+ if (TempChar == PlatformIdStr[Index2]) {
+ Index2++;
+ } else {
+ Index2 = 0;
+ }
+ if (Index2 == strlen (PlatformIdStr)) {
+ Index2 = 0;
+ Index3 = 0;
+ memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+ ReadPlatformId = TRUE;
+ }
+ } else if (ReadPlatformId) {
+ if (TempChar == '\n') {
+ ReadPlatformId = FALSE;
+ Array[Index3] = TempChar;
+ PlatformIdNum = GetNumFromAsciiString ((CHAR8 *)Array, PlatformId);
+ //
+ // Take the first defaultid an platformid as the key of this group
+ //
+ mMultiPlatformParam.KeyPlatformId[mMultiPlatformParam.KeyIdNum++] = PlatformId[0];
+ assert (DefaultIdNum == PlatformIdNum);
+ } else {
+ Array[Index3++] = TempChar;
+ }
+ }
+ //
+ //"/ PlatformIdUqi:"
+ //
+ if (!ReadPlatformIdUqi) {
+ if (TempChar == PlatformUqi[Index4]) {
+ Index4++;
+ } else {
+ Index4 = 0;
+ }
+ if (Index4 == strlen (PlatformUqi)) {
+ Index4 = 0;
+ Index3 = 0;
+ memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+ ReadPlatformIdUqi = TRUE;
+ }
+ } else if (ReadPlatformIdUqi) {
+ if (mMultiPlatformParam.Uqi.HexNum > 0) {
+ continue;
+ }
+ //
+ // Read size of UQI string
+ //
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ if (mMultiPlatformParam.Uqi.HexNum > MAX_INPUT_ALLOCATE_SIZE) {
+ return EFI_ABORTED;
+ }
+ //
+ // Malloc buffer for string size + null termination
+ //
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ free (mMultiPlatformParam.Uqi.Data);
+ mMultiPlatformParam.Uqi.Data = NULL;
+ }
+ mMultiPlatformParam.Uqi.Data = (CHAR16 *)calloc(mMultiPlatformParam.Uqi.HexNum + 1, sizeof(CHAR16));
+
+ if (mMultiPlatformParam.Uqi.Data == NULL) {
+ printf("Error. Unable to allocate 0x%04zx bytes for UQI string -- FAILURE\n", (mMultiPlatformParam.Uqi.HexNum + 1) * sizeof(CHAR16));
+ break;
+ }
+ //
+ // Read UQI string
+ //
+ for (Index = 0; Index < mMultiPlatformParam.Uqi.HexNum; Index++) {
+ if (AsciiOrUcs2 == ASCII) {
+ fscanf(ScriptFile, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
+ } else {
+ Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+ if (Char8Str == NULL) {
+ return EFI_ABORTED;
+ }
+ sscanf(Char8Str, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
+ if (Char8Str != NULL) {
+ free (Char8Str);
+ Char8Str = NULL;
+ }
+ }
+ }
+ //
+ // Set null termination
+ //
+ mMultiPlatformParam.Uqi.Data[Index] = 0;
+ ReadPlatformIdUqi = FALSE;
+ }
+
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+ //
+ // To do: Get and set DefaultId and PlatformId here!
+ //
+ default:
+ //
+ // Comment or garbage, skip to next line
+ //
+ do {
+ if (AsciiOrUcs2 == ASCII) {
+ fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+ } else {
+ fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+ if (AsciiOrUcs2 == BIG_UCS2) {
+ TempChar = (CHAR8)TempChar16;
+ } else {
+ TempChar = (CHAR8)(TempChar16 >> 8);
+ }
+ }
+ } while((TempChar != '\n') && !feof(ScriptFile));
+ break;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the offset of file name from the whole path.
+
+ @param NameStr The whole file path.
+
+ @retval Offset Return the offset of file name in path
+**/
+static
+UINTN
+GetOffsetOfFileName (
+ IN CHAR8 *NameStr
+ )
+{
+ CHAR8 *Str;
+ UINTN Index;
+ UINTN CurIndex;
+
+ Index = 0;
+ CurIndex = 0;
+ Str = NameStr;
+
+ if (NameStr == NULL) {
+ return 0;
+ }
+ while (*Str != '\0') {
+ if (*Str == OS_SEP) {
+ CurIndex = Index;
+ }
+ Str++;
+ Index++;
+ }
+ if (*(NameStr + CurIndex) == OS_SEP) {
+ return CurIndex + 1;
+ } else {
+ return 0;
+ }
+}
+/**
+ Print the questions which is updated to the current platform successfully.
+
+ Parse the Uqi List, and print it till break NULL.
+
+ @param List Pointer to a List.
+
+ @retval EFI_SUCCESS The Print was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+VOID
+PrintUpdateListInfo (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ UINT32 Index;
+ UINT32 Index1;
+ UINT32 Index2;
+ UQI_PARAM_LIST *CurList;
+
+ Index1 = 0;
+ Index2 = 0;
+ Index = 0;
+ CurList = UqiList;
+
+ printf ("\n\n -- Update List -- ");
+
+ while (CurList != NULL) {
+ if (!CurList->ErrorOrNot && CurList->ParseOrNot && !CurList->SameOrNot) {
+ ++Index;
+ printf ("\n\n[Script line %d] Update No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
+ printf ("Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ //
+ //Print the value of scripts
+ //
+ printf ("\n[ Update Value From: ");
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
+ printf ("%02x ", *(CurList->Header.DiffValue + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
+ }
+ //
+ //Print the value of current platform
+ //
+ printf (" To: ");
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
+ printf ("%02x ", *(CurList->Header.Value + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+ }
+ printf ("]");
+ }
+ CurList = CurList->Next;
+ }
+ if (Index > 1) {
+ printf ("\n\n\n[Results]: %d questions have been updated successfully in total. \n", Index);
+ } else {
+ printf ("\n\n\n[Results]: %d question has been updated successfully in total. \n", Index);
+ }
+}
+
+
+/**
+ Print the error, when update questions.
+
+ Parse the Uqi List, and print it till break NULL.
+
+ @param List The Pointer to a List.
+
+**/
+static
+BOOLEAN
+PrintErrorInfo (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ UINT32 Index1;
+ UINT32 Index2;
+ UINT32 Index;
+ UQI_PARAM_LIST *CurList;
+ BOOLEAN IsError;
+
+ Index1 = 0;
+ Index2 = 0;
+ Index = 0;
+ CurList = UqiList;
+ IsError = FALSE;
+
+ while (CurList != NULL) {
+ if (CurList->ErrorOrNot && CurList->ParseOrNot) {
+ IsError = TRUE;
+ ++Index;
+ printf ("\n\n[Script line %d] Error Information No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
+ printf ("Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ //
+ //Print the Input value of scripts
+ //
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *CurList->Header.Value; Index2++) {
+ printf ("%02x ", *(CurList->Header.Value + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+ }
+ //
+ //Print the Error information
+ //
+ if (CurList->Error != NULL) {
+ printf ("\n%s ", CurList->Error);
+ }
+ }
+ CurList = CurList->Next;
+ }
+ if (IsError) {
+ if (Index > 1) {
+ printf ("\n\n[Results]: Occurred %d errors during the update process. \n", Index);
+ } else {
+ printf ("\n\n[Results]: Occurred %d error during the update process. \n", Index);
+ }
+ }
+ return IsError;
+}
+
+/**
+ Any questions that exist in both the script and the current platform and have
+ different values will be logged to the screen.
+
+ Parse the Uqi List, and print it till break NULL.
+
+ @param List Pointer to a List.
+
+ @retval EFI_SUCCESS The Print was complete successfully
+ @return EFI_ABORTED An error occurreds
+**/
+static
+VOID
+PrintVerifiedListInfo (
+ IN UQI_PARAM_LIST *UqiList
+ )
+{
+ UINT32 Index1;
+ UINT32 Index2;
+ UINT32 Index3;
+ UINT32 Index;
+ UQI_PARAM_LIST *CurList;
+ UINT32 StrLen;
+ UINT32 StrLen1;
+ UINT32 StrLen2;
+
+ Index1 = 0;
+ Index2 = 0;
+ Index = 0;
+ StrLen = 0;
+ CurList = UqiList;
+
+ StrLen1 = strlen (mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
+ StrLen2 = strlen (mInputFdName + GetOffsetOfFileName (mInputFdName));
+
+ StrLen = (StrLen1 > StrLen2) ? StrLen1:StrLen2;
+
+ printf ("\n\n -- Different List -- ");
+
+ while (CurList != NULL) {
+ if (!CurList->SameOrNot && CurList->ParseOrNot) {
+ ++Index;
+ printf ("\n\n[Script line %d] Difference No.%d:", CurList->Header.ScriptsLine, ++Index1);
+ printf ("\n[%s", mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
+ for (Index3 = 0; Index3 < StrLen - StrLen1; Index3++) {
+ printf (" ");
+ }
+ printf ("]:");
+ printf (" Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ //
+ //Print the Input value of scripts
+ //
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
+ printf ("%02x ", *(CurList->Header.Value + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+ }
+ //
+ //Print the value of current platform
+ //
+ printf ("\n[%s", mInputFdName + GetOffsetOfFileName (mInputFdName));
+ for (Index3 = 0; Index3 < StrLen - StrLen2; Index3++) {
+ printf (" ");
+ }
+ printf ("]:");
+ printf (" Q %04x ", CurList->Header.HexNum);
+ for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+ printf ("%04x ", CurList->Header.Data[Index2]);
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ printf ("ORDERED_LIST ");
+ } else if (CurList->Header.Type == CHECKBOX) {
+ printf ("CHECKBOX ");
+ } else if (CurList->Header.Type == ONE_OF) {
+ printf ("ONE_OF ");
+ } else if (CurList->Header.Type == NUMERIC) {
+ printf ("NUMERIC ");
+ } else if (CurList->Header.Type == STRING) {
+ printf ("STRING ");
+ } else {
+ printf ("UNKNOWN ");
+ }
+ if (CurList->Header.Type == ORDERED_LIST) {
+ for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
+ printf ("%02x ", *(CurList->Header.DiffValue + Index2));
+ }
+ } else if (CurList->Header.Type == STRING) {
+ printf("\"");
+ WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
+ printf("\"");
+ } else {
+ printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
+ }
+ }
+ CurList = CurList->Next;
+ }
+ if (Index > 1) {
+ printf (
+ "\n\n\n[Results]: There are %d differences between '%s' and '%s' in total.\n\n\n",
+ Index,
+ mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
+ mInputFdName + GetOffsetOfFileName (mInputFdName)
+ );
+ } else {
+ printf (
+ "\n\n\n[Results]: There is %d difference between '%s' and '%s' in total.\n\n\n",
+ Index,
+ mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
+ mInputFdName + GetOffsetOfFileName (mInputFdName)
+ );
+ }
+}
+
+/**
+ Insert Uqi object to the end of unidirection List.
+
+ @param InList The Pointer to the current object
+ @param UqiListEntry The pointer to the entry of UqiList
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertUnidirectionList (
+ IN UQI_PARAM_LIST *InList,
+ IN UQI_PARAM_LIST **UqiListEntry
+ )
+{
+ UQI_PARAM_LIST **UqiCurList;
+ UQI_PARAM_LIST *UqiNext;
+
+ UqiCurList = NULL;
+ UqiNext = NULL;
+
+ if (UqiListEntry == NULL) {
+ return EFI_ABORTED;
+ }
+ //
+ // Insert to Uqi Node to UqiList
+ //
+ UqiCurList = UqiListEntry;
+ UqiNext = *UqiCurList;
+ if (UqiNext == NULL) {
+ //
+ //Insert is the first node as node header
+ //
+ *UqiCurList = InList;
+ } else {
+ while ((UqiNext != NULL) && (UqiNext->Next != NULL)) {
+ UqiNext = UqiNext->Next;
+ }
+ UqiNext->Next = InList;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Free variable unidirection List.
+
+ @param UqiListEntry The pointer to the entry of UqiList
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+FreeUnidirectionList (
+ IN UQI_PARAM_LIST *UqiListEntry
+ )
+{
+ UQI_PARAM_LIST *Next;
+
+ Next = NULL;
+ //
+ // Free Uqi List
+ //
+ while (UqiListEntry != NULL) {
+ Next = UqiListEntry->Next;
+ if (UqiListEntry->Header.Value != NULL) {
+ free (UqiListEntry->Header.Value);
+ }
+ if (UqiListEntry->Header.DiffValue != NULL) {
+ free (UqiListEntry->Header.DiffValue);
+ }
+ if (UqiListEntry->Header.Data != NULL) {
+ free (UqiListEntry->Header.Data);
+ }
+ if (UqiListEntry->Header.DefaultId != NULL) {
+ free (UqiListEntry->Header.DefaultId);
+ }
+ if (UqiListEntry->Header.PlatformId != NULL) {
+ free (UqiListEntry->Header.PlatformId);
+ }
+ if (UqiListEntry->Error != NULL) {
+ free (UqiListEntry->Error);
+ }
+ free (UqiListEntry);
+ UqiListEntry = Next;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a directory and files in it.
+
+ @param DirName Name of the directory need to be deleted.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LibRmDir (
+ IN CHAR8* DirName
+)
+{
+ CHAR8* SystemCommand;
+
+ SystemCommand = NULL;
+
+ if (DirName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete a directory and files in it.
+ //
+
+ SystemCommand = malloc (
+ strlen (RMDIR_STR) +
+ strlen (DirName) +
+ 1
+ );
+ if (SystemCommand == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ sprintf (
+ SystemCommand,
+ RMDIR_STR,
+ DirName
+ );
+
+ system (SystemCommand);
+ free(SystemCommand);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pick up the FFS from the FD image.
+
+ Call BfmLib to get all FFS in one FD image, and save all which includes IFR
+ Binary to gEfiFdInfo structure.
+
+ @retval EFI_SUCCESS Get the address successfully.
+**/
+static
+EFI_STATUS
+PickUpFfsFromFd (
+ VOID
+ )
+{
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SystemCommand;
+ CHAR8 *TempSystemCommand;
+ CHAR8 *TemDir;
+ EFI_STATUS Status;
+ INT32 ReturnValue;
+
+ Status = EFI_SUCCESS;
+ SystemCommandFormatString = NULL;
+ SystemCommand = NULL;
+ TempSystemCommand = NULL;
+ TemDir = NULL;
+ ReturnValue = 0;
+
+ memset (&gEfiFdInfo, 0, sizeof (G_EFI_FD_INFO));
+ //
+ // Construction 'system' command string
+ //
+ SystemCommandFormatString = "BfmLib -e \"%s\" ";
+
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ printf ("Fail to allocate memory.\n");
+ return EFI_ABORTED;
+ }
+
+ sprintf (
+ SystemCommand,
+ "BfmLib -e \"%s\" ",
+ mInputFdName
+ );
+
+ if (mFullGuidToolDefinitionDir[0] != 0) {
+ TempSystemCommand = SystemCommand;
+ SystemCommand = malloc (
+ strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (TempSystemCommand) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ free (TempSystemCommand);
+ return EFI_UNSUPPORTED;
+ }
+ strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+ strcat (SystemCommand, OS_SEP_STR);
+ strcat (SystemCommand, TempSystemCommand);
+ free (TempSystemCommand);
+
+ }
+
+ //
+ // Call BfmLib to get all FFS in Temp folder of current path
+ //
+ ReturnValue = system (SystemCommand);
+ free (SystemCommand);
+ if (ReturnValue == -1) {
+ printf ("Error. Call BfmLib failed.\n");
+ return EFI_ABORTED;
+ }
+ //
+ //Pick up the FFS which is interrelated with the IFR binary.
+ //
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME)> _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return EFI_ABORTED;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ mMultiPlatformParam.ExistStorageFfsInBfv = FALSE;
+ Status = FindFileInFolder (TemDir, &mMultiPlatformParam.ExistStorageFfsInBfv, &mMultiPlatformParam.SizeOptimized);
+
+ return Status;
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+/**
+ Generate pre-defined guided tools data.
+
+ @return An EFI_HANDLE contain guided tools data.
+
+**/
+static
+EFI_HANDLE
+PreDefinedGuidedTools (
+ VOID
+)
+{
+ EFI_GUID Guid;
+ STRING_LIST *Tool;
+ GUID_SEC_TOOL_ENTRY *FirstGuidTool;
+ GUID_SEC_TOOL_ENTRY *LastGuidTool;
+ GUID_SEC_TOOL_ENTRY *NewGuidTool;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = {
+ "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress",
+ "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress",
+ "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32",
+ "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress"
+ };
+
+ Tool = NULL;
+ FirstGuidTool = NULL;
+ LastGuidTool = NULL;
+ NewGuidTool = NULL;
+
+ for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) {
+ Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]);
+ if ((Tool != NULL) &&
+ (Tool->Count == 3)
+ ) {
+ Status = StringToGuid (Tool->Strings[0], &Guid);
+ if (!EFI_ERROR (Status)) {
+ NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
+ if (NewGuidTool != NULL) {
+ memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
+ NewGuidTool->Name = CloneString(Tool->Strings[1]);
+ NewGuidTool->Path = CloneString(Tool->Strings[2]);
+ NewGuidTool->Next = NULL;
+ } else {
+ printf ( "Fail to allocate memory. \n");
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ }
+ return NULL;
+ }
+ if (FirstGuidTool == NULL) {
+ FirstGuidTool = NewGuidTool;
+ } else {
+ LastGuidTool->Next = NewGuidTool;
+ }
+ LastGuidTool = NewGuidTool;
+ }
+
+ } else {
+ fprintf (stdout, "Error");
+ }
+ if (Tool != NULL) {
+ FreeStringList (Tool);
+ Tool = NULL;
+ }
+ }
+ return FirstGuidTool;
+}
+
+/**
+ Read all storages under a specified platformId and defaultId from BFV.
+
+ @param Binary The pointer to the buffer of binary.
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadStorageFromBinary (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ UINT32 Length;
+ UINT8 *DataBase;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ Length = 0;
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ //
+ // Judge the layout of NV by Variable Guid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore ((VOID *)(DataBase + *(UINT16 *)DataBase));
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot ((VOID *)(DataBase + *(UINT16 *)DataBase));
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Read variable with Monotonic based layout from binary
+ //
+ Length = ReadMonotonicBasedVariableToList (Binary, StorageListEntry);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Read variable with time-based layout from binary
+ //
+ Length = ReadTimeBasedVariableToList (Binary, StorageListEntry);
+ } else {
+ //
+ // Read variable with normal layout from binary
+ //
+ Length = ReadVariableToList (Binary, StorageListEntry);
+ }
+
+ return Length;
+}
+
+/**
+ Insert one storage to the raw bianry, and return its length.
+
+ @param Storage The pointer to a storage in storage list.
+ @param Binary The pointer to the buffer of binary.
+
+ @return length The length of storage
+**/
+UINT32
+PutStorageToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ UINT32 Length;
+ UINT32 Index;
+ UINT8 *BinaryBeginning;
+ FORMSET_STORAGE *CurStorage;
+ LIST_ENTRY *StorageLink;
+ VOID *VariableStoreHeader;
+ BOOLEAN AuthencitatedMonotonicOrNot;
+ BOOLEAN AuthencitatedBasedTimeOrNot;
+
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ Length = 0;
+ Index = 0;
+ BinaryBeginning = Binary;
+ VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ AuthencitatedMonotonicOrNot = FALSE;
+ AuthencitatedBasedTimeOrNot = FALSE;
+ //
+ // Judge the layout of NV by gEfiVariableGuid
+ //
+ AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore (VariableStoreHeader);
+ AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+ //
+ // Build the binary for BFV
+ //
+ StorageLink = GetFirstNode (StorageListEntry);
+
+ while (!IsNull (StorageListEntry, StorageLink)) {
+ CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if ((CurStorage->DefaultId[0] == Storage->DefaultId[0])
+ && (CurStorage->PlatformId[0] == Storage->PlatformId[0])
+ && !CurStorage->Skip
+ ) {
+ CurStorage->Skip = TRUE;
+
+ if (AuthencitatedMonotonicOrNot) {
+ //
+ // Copy variable with Monotonic based layout to binary
+ //
+ Length = CopyMonotonicBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
+ } else if (AuthencitatedBasedTimeOrNot){
+ //
+ // Copy variable with time-based layout to binary
+ //
+ Length = CopyTimeBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
+ } else {
+ //
+ // Copy variable with normall layout to binary
+ //
+ Length = CopyVariableToBinary (CurStorage, BinaryBeginning, Index);
+ }
+ Index++;
+ }
+ StorageLink = GetNextNode (StorageListEntry, StorageLink);
+ }
+ //
+ // Fix the length of storage header under a specified DefaultId and PlatformId
+ //
+ if (AuthencitatedMonotonicOrNot) {
+ FixMontonicVariableHeaderSize (BinaryBeginning, Length);
+ } else if (AuthencitatedBasedTimeOrNot){
+ FixBasedTimeVariableHeaderSize (BinaryBeginning, Length);
+ } else {
+ FixVariableHeaderSize (BinaryBeginning, Length);
+ }
+ return Length;
+}
+
+/**
+ Insert one storage to Fd's NvStoreDatabase, and return its length.
+
+ @param Storage The pointer to a storage in storage list.
+ @param Binary The pointer to the buffer of binary.
+
+ @return length The length of storage
+**/
+UINT32
+PutStorageToNvStoreBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ UINT32 Length;
+ UINT32 Index;
+ UINT8 *BinaryBeginning;
+ FORMSET_STORAGE *CurStorage;
+ LIST_ENTRY *StorageLink;
+
+ Length = 0;
+ Index = 0;
+ BinaryBeginning = Binary;
+ //
+ // Build the binary for NvStorDatabase
+ //
+ StorageLink = GetFirstNode (StorageListEntry);
+ while (!IsNull (StorageListEntry, StorageLink)) {
+ CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if ((CurStorage->PlatformId[0] == Storage->PlatformId[0])
+ && (CurStorage->DefaultId[0] == Storage->DefaultId[0])
+ && !CurStorage->Skip
+ ) {
+ CurStorage->Skip = TRUE;
+ Length = CopyVariableToNvStoreBinary (CurStorage, BinaryBeginning, Index);
+ Index++;
+ }
+ StorageLink = GetNextNode (StorageListEntry, StorageLink);
+ }
+ // Alignment
+ Length = (Length + 3) & ~3;
+ FixNvStoreVariableHeaderSize (BinaryBeginning, Length);
+ return Length;
+}
+
+/**
+ Optimize the Delta binary size based on the default setting binary, and
+ create a new binary with new size on the Storage.ffs.
+
+ @param DefaultBinary The pointer to a default setting binary
+ @param DefaultHeaderLen The header lenght of default setting binary
+ @param DeltaBinary The pointer to a delta setting binary
+ @param CurrentSize The size of current delta data.
+
+ @return length The length of new storage
+**/
+UINT32
+OptimizeStorageDeltaData (
+ IN UINT8 *DefaultBinary,
+ IN UINT8 *CurrentBinary,
+ IN OUT UINT8 *DeltaBinary,
+ IN UINT32 CurrentSize
+ )
+{
+ UINT32 Size;
+ UINT16 Index;
+ UINT32 DefaultHeaderSize;
+ UINT32 DeltaHeaderSize;
+ UINT32 AlignSize;
+ PCD_DATA_DELTA DeltaData;
+ DefaultHeaderSize = ((PCD_DEFAULT_DATA *)DefaultBinary)->HeaderSize + 4;
+ DeltaHeaderSize = ((PCD_DEFAULT_DATA *)CurrentBinary)->HeaderSize + 4;
+ //
+ // Copy the Delta Header directly
+ //
+ Size = DeltaHeaderSize;
+ memcpy (DeltaBinary, CurrentBinary, Size);
+ //
+ // Compare the delta data and optimize the size
+ //
+ for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
+ if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
+ DeltaData.Offset = Index;
+ DeltaData.Value = *(CurrentBinary + DeltaHeaderSize + Index);
+ memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
+ Size = Size + sizeof(DeltaData);
+ }
+ }
+ *(UINT32 *)DeltaBinary = Size;
+ AlignSize = (Size + 7) & ~7;
+ //set Alignment data 0x00
+ for (Index = 0; Index < AlignSize - Size; Index++){
+ *(DeltaBinary + Size + Index) = 0x0;
+ }
+ return Size;
+}
+
+/**
+ Optimize the Delta binary size based on the default setting binary, and
+ create a new binary with new size on the Storage.ffs.
+
+ @param DefaultBinary The pointer to a default setting binary
+ @param DefaultHeaderLen The header lenght of default setting binary
+ @param DeltaBinary The pointer to a delta setting binary
+ @param CurrentSize The size of current delta data.
+
+ @return length The length of new storage
+**/
+UINT32
+OptimizeStorageSection (
+ IN UINT8 *DefaultBinary,
+ IN UINT8 *CurrentBinary,
+ IN OUT UINT8 *DeltaBinary,
+ IN UINT32 CurrentSize
+ )
+{
+ UINT32 Size;
+ UINT16 Index;
+ UINT32 DefaultHeaderSize;
+ UINT32 DeltaHeaderSize;
+ DATA_DELTA DeltaData;
+
+ DefaultHeaderSize = *(UINT16 *)DefaultBinary;
+ DeltaHeaderSize = *(UINT16 *)CurrentBinary;
+
+ //
+ // Copy the Delta Header directly
+ //
+ Size = DeltaHeaderSize;
+ memcpy (DeltaBinary, CurrentBinary, Size);
+ //
+ // Compare the delta data and optimize the size
+ //
+ for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
+ if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
+ DeltaData.Offset = Index;
+ DeltaData.Value = *(CurrentBinary + DeltaHeaderSize + Index);
+ memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
+ Size = Size + sizeof(DeltaData);
+ }
+ }
+ return Size;
+}
+
+/**
+ Create the storage section and copy it to memory.
+
+ @param Buffer The pointer to the buffer
+ @param Size The size of input buffer.
+
+ @return the new size
+**/
+UINT32
+CreateStorageSection (
+ IN OUT UINT8 *Buffer,
+ IN UINT32 Size,
+ IN CHAR8 *FileName
+)
+{
+ FILE *BinaryFd;
+ UINTN BytesWrite;
+ UINT32 SectionSize;
+
+ BinaryFd = NULL;
+ //
+ // Create the raw section files in FFS
+ //
+ BinaryFd = fopen (FileName, "wb+");
+ if (BinaryFd == NULL) {
+ printf ("Error. Failed to create the raw data section.\n");
+ return 0;
+ }
+ fseek (BinaryFd, 0, SEEK_SET);
+ BytesWrite = fwrite (Buffer, sizeof (CHAR8), Size, BinaryFd);
+ fclose (BinaryFd);
+ if (BytesWrite != Size) {
+ printf ("Error. Failed to write the raw data section.\n");
+ return 0;
+ }
+ CreateRawSection (FileName, FileName);
+
+ BinaryFd = fopen (FileName, "rb");
+ if (BinaryFd == NULL) {
+ printf ("Error. Failed to open the raw data section.\n");
+ return 0;
+ }
+ fseek (BinaryFd, 0, SEEK_SET);
+ BytesWrite = fread (Buffer, sizeof (CHAR8), (Size + sizeof (EFI_COMMON_SECTION_HEADER)), BinaryFd);
+ fclose (BinaryFd);
+ if (BytesWrite != (Size + sizeof (EFI_COMMON_SECTION_HEADER))) {
+ printf ("Error. Failed to read the raw data section.\n");
+ return 0;
+ }
+
+ SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)Buffer)->Size);
+ return SectionSize;
+}
+
+/**
+ Read NvStoreDataBase and insert it to the Storage list.
+
+ @param InputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+ReadStorageFromNvStoreDatabase (
+ IN LIST_ENTRY *VarListEntry
+)
+{
+
+ UINT8 *Binary;
+ UINT8 *FullBinary;
+ UINT8 *VarDataBinary;
+ UINT8 *PreVarDataBinary;
+ UINT8 *DataBase;
+ PCD_DEFAULT_DATA *DeltaVarStoreHeader;
+ PCD_DEFAULT_DATA *PrePcdDefaultData;
+ UINT8 *DeltaData;
+ UINT32 DeltaSize;
+ UINT32 DataSize;
+ UINT32 HeaderSize;
+ UINT32 BinaryLength;
+ UINT32 Size;
+ UINT32 PreVarDataSize;
+ PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
+ UINT32 Offset;
+ UINT32 Value;
+ UINT32 Index;
+
+ BinaryLength = 0;
+ Binary = NULL;
+ FullBinary = NULL;
+ DataBase = NULL;
+ DeltaVarStoreHeader = NULL;
+ PreVarDataBinary = NULL;
+ PreVarDataSize = 0;
+ DeltaSize = 0;
+ Size = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER);
+ VarDataBinary = NULL;
+
+ //
+ // Check whether the FD has included the storage FFS
+ //
+ //if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
+ // return EFI_ABORTED;
+ //}
+ NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)gEfiFdInfo.NvStoreDatabase;
+ BinaryLength = NvStoreHeader->Length;
+ Binary = (UINT8 *)gEfiFdInfo.NvStoreDatabase;
+ //
+ // If detect size optimized format, transfer it to normal format
+ // before parse it
+ //
+ if (mMultiPlatformParam.SizeOptimized) {
+ FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
+ if (FullBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ }
+ while (Size < BinaryLength) {
+ DataBase = Binary + Size;
+ DataSize = *(UINT32 *)DataBase;
+ if (Size == sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
+ PrePcdDefaultData = (PCD_DEFAULT_DATA *) DataBase;
+ HeaderSize = PrePcdDefaultData->HeaderSize;
+ PreVarDataSize = DataSize - 4 - HeaderSize;
+ VarDataBinary = malloc(DataSize);
+ if (VarDataBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (VarDataBinary, DataBase, DataSize);
+ PreVarDataBinary = malloc(DataSize - 4 - HeaderSize);
+ if (PreVarDataBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ memcpy (PreVarDataBinary, DataBase + 4 + HeaderSize , DataSize - 4 - HeaderSize);
+ } else {
+ DeltaVarStoreHeader = (PCD_DEFAULT_DATA *)DataBase;
+ DeltaSize = DeltaVarStoreHeader->DataSize;
+ HeaderSize = DeltaVarStoreHeader->HeaderSize;
+ DeltaData = (UINT8*) DeltaVarStoreHeader;
+
+ VarDataBinary = malloc(PreVarDataSize + HeaderSize + 4);
+ if (VarDataBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ //
+ // Copy the default setting data
+ //
+ memcpy (VarDataBinary, DataBase, HeaderSize + 4);
+ memcpy (VarDataBinary + HeaderSize + 4, PreVarDataBinary, PreVarDataSize);
+ //
+ // Merge the delta data with default setting to get the full delta data
+ //
+ for (Index = 0; Index < (DeltaSize - HeaderSize - 4)/sizeof(PCD_DATA_DELTA); Index++) {
+ Offset = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Offset;
+ Value = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Value;
+ if (*(VarDataBinary + HeaderSize + 4 + Offset) != Value) {
+ *(VarDataBinary + HeaderSize + 4 + Offset) = (UINT8)Value;
+ }
+ }
+ }
+ //
+ // Store the Variable Data to VarListEntry
+ //
+
+ ReadNvStoreVariableToList(VarDataBinary, VarListEntry);
+ Size += (DataSize + 7) & ~7;
+ }
+
+ if (VarDataBinary != NULL) {
+ free (VarDataBinary);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read FFS from BFV and insert it to the Storage list.
+
+ @param InputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+ReadStorageFromBfv (
+ IN LIST_ENTRY *VarListEntry
+)
+{
+
+ UINT8 *Binary;
+ UINT8 *FullBinary;
+ UINT8 *DataBase;
+ UINT8 *PreVarStoreHeader;
+ DATA_DELTA *DeltaVarStoreHeader;
+ UINT8 *DeltaData;
+ UINT32 PreDataSize;
+ UINT32 DeltaSize;
+ UINT32 BinaryLength;
+ UINT32 Size;
+ UINT32 SectionSize;
+ UINT32 FullSectionLen;
+ UINT32 FullSectionSize;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINT16 Offset;
+ UINT8 Value;
+ UINT32 Index;
+ CHAR8 *SectionName;
+
+ BinaryLength = 0;
+ Binary = NULL;
+ FullBinary = NULL;
+ DataBase = NULL;
+ PreVarStoreHeader = NULL;
+ DeltaVarStoreHeader = NULL;
+ PreDataSize = 0;
+ DeltaSize = 0;
+ FullSectionSize = 0;
+ Size = sizeof (EFI_FFS_FILE_HEADER);
+ FfsHeader = NULL;
+ FullSectionLen = 0;
+ SectionName = NULL;
+
+ SectionName = getcwd(NULL, _MAX_PATH);
+ if (strlen (SectionName) + 2 * strlen (OS_SEP_STR) + strlen ("Temp") + strlen ("TempSection.sec") >
+ _MAX_PATH - 1) {
+ printf ("Error. The current path is too long.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ sprintf (SectionName + strlen (SectionName), "%cTemp%cTempSection.sec", OS_SEP, OS_SEP);
+ //
+ // Check whether the FD has included the storage FFS
+ //
+ if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
+ return EFI_ABORTED;
+ }
+ FfsHeader = (EFI_FFS_FILE_HEADER *)gEfiFdInfo.StorageFfsInBfv;
+ BinaryLength = FvBufExpand3ByteSize (FfsHeader->Size);
+ Binary = (UINT8 *)FfsHeader;
+ //
+ // If detect size optimized format, transfer it to normal format
+ // before parse it
+ //
+ if (mMultiPlatformParam.SizeOptimized) {
+ FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
+ if (FullBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ return EFI_ABORTED;
+ }
+ while (Size < BinaryLength) {
+ SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)(Binary + Size))->Size);
+ DataBase = Binary + Size + sizeof (EFI_COMMON_SECTION_HEADER);
+ if (Size == sizeof (EFI_FFS_FILE_HEADER)) {
+ PreVarStoreHeader = DataBase + *(UINT16 *)DataBase;
+ PreDataSize = SectionSize - (*(UINT16 *)DataBase + sizeof(EFI_COMMON_SECTION_HEADER));
+ memcpy (FullBinary, DataBase, SectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
+ FullSectionLen = CreateStorageSection (FullBinary, *(UINT16 *)DataBase + PreDataSize, SectionName);
+ } else {
+ DeltaVarStoreHeader = (DATA_DELTA *)(DataBase + *(UINT16 *)DataBase);
+ DeltaSize = *(UINT16 *)DataBase + PreDataSize;
+ DeltaData = FullBinary + FullSectionSize + *(UINT16 *)DataBase;
+ //
+ // Copy the DefaultId and PlatformId directly
+ //
+ memcpy (FullBinary + FullSectionSize, DataBase, *(UINT16 *)DataBase);
+ //
+ // Copy the default setting data
+ //
+ memcpy (DeltaData, PreVarStoreHeader, PreDataSize);
+ //
+ // Merge the delta data with default setting to get the full delta data
+ //
+ for (Index = 0; Index < (SectionSize - *(UINT16 *)DataBase - sizeof(EFI_COMMON_SECTION_HEADER))/sizeof(DATA_DELTA); Index++) {
+ Offset = (DeltaVarStoreHeader + Index)->Offset;
+ Value = (DeltaVarStoreHeader + Index)->Value;
+ if (*(DeltaData + Offset) != Value) {
+ *(DeltaData + Offset) = Value;
+ }
+ }
+ FullSectionLen = CreateStorageSection (FullBinary + FullSectionSize, DeltaSize, SectionName);
+ }
+ //
+ // Store the previous binary information
+ //
+ DataBase = FullBinary + FullSectionSize + sizeof (EFI_COMMON_SECTION_HEADER);
+ PreVarStoreHeader = DataBase + *(UINT16 *)DataBase;
+
+ Size += (SectionSize + 3) & ~3;
+ FullSectionSize += (FullSectionLen + 3) & ~3;;
+ }
+ //
+ // Update to the new size
+ //
+ BinaryLength = FullSectionSize;
+ Binary = FullBinary;
+ Size = 0;
+ }
+
+ //
+ // Read the storage from BFV and insert to storage list
+ //
+ while (Size < BinaryLength) {
+ SectionSize = ReadStorageFromBinary ((Binary + Size), VarListEntry);
+ Size += (SectionSize + 3) & ~3;
+ }
+ if (FullBinary != NULL) {
+ free (FullBinary);
+ }
+
+ return EFI_SUCCESS;
+}
+
+#define SIZE_64K 0x10000
+
+/**
+ Create the storage and insert it to BFV by calling BfmLib.
+
+ @param InputFdName The pointer to the input fd name.
+ @param OutputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertBinaryToBfv (
+ IN CHAR8 *InputFdName,
+ IN CHAR8 *OutputFdName,
+ IN LIST_ENTRY *VarListEntry
+)
+{
+ UINT8 *Binary;
+ UINT8 *PreBinary;
+ UINT32 BinaryLength;
+ UINT32 PreBinaryLength;
+ UINT32 OptimizedBinaryLength;
+ UINT32 Size;
+ UINT32 OptimizedSize;
+ EFI_STATUS Status;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ CHAR8 *SystemCommandFormatString;
+ CHAR8 *SectionNameFormatString;
+ CHAR8 *SystemCommand;
+ CHAR8 *TempSystemCommand;
+ INT32 ReturnValue;
+ CHAR8 *FileName;
+ BOOLEAN SizeOptimizedFlag;
+ CHAR8 *SectionName[_MAXIMUM_SECTION_FILE_NUM];
+ UINT32 Index;
+ CHAR8 *TemDir;
+ //
+ // Workaround for static code checkers.
+ // Ensures the size of 'IndexStr' can hold all the digits of an unsigned
+ // 32-bit integer.
+ //
+ CHAR8 IndexStr[16];
+
+ BinaryLength = 0;
+ PreBinaryLength = 0;
+ Storage = NULL;
+ StorageLink = NULL;
+ Binary = NULL;
+ PreBinary = NULL;
+ Size = 0;
+ OptimizedSize = 0;
+ Status = EFI_SUCCESS;
+ SystemCommandFormatString = NULL;
+ SectionNameFormatString = NULL;
+ SystemCommand = NULL;
+ TempSystemCommand = NULL;
+ SizeOptimizedFlag = FALSE;
+ Index = 0;
+ FileName = NULL;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ SectionNameFormatString = "%s%cTemp%c%s.sec";
+
+ memset (SectionName, 0, _MAXIMUM_SECTION_FILE_NUM * sizeof(CHAR8 *));
+ FileName = malloc (strlen (TemDir) + 1 + strlen ("Storage.ffs") + 1);
+ if (FileName == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (FileName, "%s%cStorage.ffs", TemDir, OS_SEP);
+ //
+ // Allocate the buffer which is the same with the input FD
+ //
+ Binary = malloc (SIZE_64K);
+ if (Binary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ PreBinary = malloc (SIZE_64K);
+ if (PreBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // If already existed a Storage.ffs in FD, keep the same format when execute update operation whatever input -a or not -a options.
+ //
+ if (mMultiPlatformParam.SizeOptimized
+ || (!mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam)
+ ) {
+ SizeOptimizedFlag = TRUE;
+ } else if (mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam && !mMultiPlatformParam.SizeOptimized) {
+ printf ("\nWarning. The \"-a\" parameter is ignored.\n");
+ }
+ //
+ // Build the binary for BFV
+ //
+ StorageLink = GetFirstNode (VarListEntry);
+
+ while (!IsNull (VarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (!Storage->Skip) {
+ //
+ // Assign the section name under the Temp directory
+ //
+ sprintf (IndexStr, "%d", Index);
+ SectionName[Index] = calloc (
+ strlen (SectionNameFormatString) + strlen (TemDir) + strlen(IndexStr) + 1,
+ sizeof(CHAR8)
+ );
+ if (SectionName[Index] == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SectionName[Index],
+ "%s%cTemp%c%s.sec",
+ TemDir,
+ OS_SEP,
+ OS_SEP,
+ IndexStr
+ );
+ memset(Binary, 0, SIZE_64K);
+ Size = PutStorageToBinary (Storage, Binary, VarListEntry);
+ assert (Size < SIZE_64K);
+ //
+ // Re-calculate the storage section by size optimization
+ //
+ if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+ OptimizedSize = OptimizeStorageSection (
+ PreBinary + sizeof (EFI_COMMON_SECTION_HEADER),
+ Binary,
+ PreBinary + PreBinaryLength,
+ Size
+ );
+ if (OptimizedSize == 0) {
+ printf ("Error. Failed to optimize the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+ //
+ // Create the raw section with normal format
+ //
+ assert (Size < SIZE_64K - sizeof (EFI_COMMON_SECTION_HEADER));
+ BinaryLength = CreateStorageSection (Binary, Size, SectionName[Index]);
+ if (BinaryLength == 0) {
+ printf ("Error. Failed to create the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ assert (BinaryLength < SIZE_64K);
+
+ //
+ // Create the raw section with optimized format
+ //
+ if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+ OptimizedBinaryLength = CreateStorageSection (PreBinary + PreBinaryLength, OptimizedSize, SectionName[Index]);
+ if (OptimizedBinaryLength == 0) {
+ printf ("Error. Failed to create the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ }
+ PreBinaryLength = BinaryLength;
+ memcpy (PreBinary, Binary, PreBinaryLength);
+ Index++;
+ }
+ StorageLink = GetNextNode (VarListEntry, StorageLink);
+ }
+ //
+ // Create the raw ffs by GenFfs
+ //
+ CreateRawFfs (&SectionName[0], FileName, SizeOptimizedFlag);
+
+ //
+ // Call BfmLib to insert this binary into the BFV of FD.
+ //
+ //
+ // Construction 'system' command string
+ //
+ if (mMultiPlatformParam.ExistStorageFfsInBfv) {
+ if (mFvNameGuidString != NULL) {
+ SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\" -g %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -r \"%s\" \"%s\" \"%s\" -g %s",
+ mInputFdName,
+ FileName,
+ mOutputFdName,
+ mFvNameGuidString
+ );
+ } else {
+ SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -r \"%s\" \"%s\" \"%s\"",
+ mInputFdName,
+ FileName,
+ mOutputFdName
+ );
+ }
+ } else {
+ if (mFvNameGuidString != NULL) {
+ SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\" -g %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -i \"%s\" \"%s\" \"%s\" -g %s",
+ mInputFdName,
+ FileName,
+ mOutputFdName,
+ mFvNameGuidString
+ );
+ } else {
+ SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\"";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
+ );
+ if (SystemCommand == NULL) {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ sprintf (
+ SystemCommand,
+ "BfmLib -i \"%s\" \"%s\" \"%s\"",
+ mInputFdName,
+ FileName,
+ mOutputFdName
+ );
+ }
+ }
+
+ if (mFullGuidToolDefinitionDir[0] != 0) {
+ TempSystemCommand = SystemCommand;
+ SystemCommand = malloc (
+ strlen (mFullGuidToolDefinitionDir) + strlen ("\\") + strlen (TempSystemCommand ) + 1
+ );
+
+ if (SystemCommand == NULL) {
+ free (TempSystemCommand);
+ goto Done;
+ }
+ strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+ strcat (SystemCommand, OS_SEP_STR);
+ strcat (SystemCommand, TempSystemCommand);
+ free (TempSystemCommand);
+ }
+
+ ReturnValue = system (SystemCommand);
+ free (SystemCommand);
+ remove (FileName);
+ if (ReturnValue == -1) {
+ Status = EFI_ABORTED;
+ }
+Done:
+ for (Index = 0; SectionName[Index] != NULL; Index++) {
+ free (SectionName[Index]);
+ }
+ if (PreBinary != NULL) {
+ free (PreBinary);
+ }
+ if (Binary) {
+ free (Binary);
+ }
+ return Status;
+}
+
+/**
+ Create the storage and insert it to NvStoreDatabase.
+
+ @param InputFdName The pointer to the input fd name.
+ @param OutputFdName The pointer to the input fd name.
+ @param VarListEntry The pointer to the variable list.
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertBinaryToNvStoreDatabase (
+ IN CHAR8 *InputFdName,
+ IN CHAR8 *OutputFdName,
+ IN LIST_ENTRY *VarListEntry
+)
+{
+ UINT8 *Binary;
+ UINT8 *PreBinary;
+ UINT8 *NvStoreDatabaseBuffer;
+ UINT32 PreBinaryLength;
+ UINT32 Size;
+ UINT32 NvStoreDatabaseSize;
+ UINT32 OptimizedSize;
+ EFI_STATUS Status;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN SizeOptimizedFlag;
+ PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreBufferHeader;
+ PCD_DEFAULT_DATA *PcdDefaultData;
+
+ //
+ // Workaround for static code checkers.
+ // Ensures the size of 'IndexStr' can hold all the digits of an unsigned
+ // 32-bit integer.
+ //
+
+ PreBinaryLength = 0;
+ Storage = NULL;
+ StorageLink = NULL;
+ Binary = NULL;
+ PreBinary = NULL;
+ NvStoreDatabaseBuffer = NULL;
+ PcdDefaultData = NULL;
+ Size = 0;
+ NvStoreDatabaseSize = 0;
+ OptimizedSize = 0;
+ Status = EFI_SUCCESS;
+ SizeOptimizedFlag = FALSE;
+
+ //
+ // Allocate the buffer which is the same with the input FD
+ //
+
+ Binary = malloc (SIZE_64K);
+ if (Binary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ NvStoreBufferHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *) gEfiFdInfo.NvStoreDatabase;
+ NvStoreDatabaseBuffer = malloc (NvStoreBufferHeader->MaxLength);
+ if (NvStoreDatabaseBuffer == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ memcpy(NvStoreDatabaseBuffer, gEfiFdInfo.NvStoreDatabase, NvStoreBufferHeader->MaxLength);
+ PreBinary = malloc (SIZE_64K);
+ if (PreBinary == NULL) {
+ printf ("Error. Memory allocation failed.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ SizeOptimizedFlag = TRUE;
+ } else {
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //
+ // Build the binary for BFV
+ //
+ StorageLink = GetFirstNode (VarListEntry);
+ while (!IsNull (VarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (!Storage->Skip) {
+ memset(Binary, 0, SIZE_64K);
+ Size = PutStorageToNvStoreBinary (Storage, Binary, VarListEntry);
+ assert (Size < SIZE_64K);
+ //
+ // Re-calculate the storage section by size optimization
+ //
+ if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+ OptimizedSize = OptimizeStorageDeltaData (
+ PreBinary,
+ Binary,
+ NvStoreDatabaseBuffer + NvStoreDatabaseSize,
+ Size
+ );
+ if (OptimizedSize == 0) {
+ printf ("Error. Failed to optimize the storage section.\n");
+ Status = EFI_ABORTED;
+ goto Done;
+ }
+ //Alignment
+ OptimizedSize = (OptimizedSize + 7) & ~7;
+ NvStoreDatabaseSize += OptimizedSize;
+ } else {
+ //Alignment
+ Size = (Size + 7) & ~7;
+ PcdDefaultData = (PCD_DEFAULT_DATA *)Binary;
+ memcpy(NvStoreDatabaseBuffer + sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER), Binary, Size + PcdDefaultData->HeaderSize + 4 );
+ PreBinaryLength = Size + PcdDefaultData->HeaderSize + 4;
+ NvStoreDatabaseSize = sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + PreBinaryLength;
+ memcpy(PreBinary, Binary, PreBinaryLength);
+ }
+ }
+ StorageLink = GetNextNode (VarListEntry, StorageLink);
+ }
+ if (NvStoreBufferHeader->Length != NvStoreDatabaseSize) {
+ ((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)NvStoreDatabaseBuffer)->Length = NvStoreDatabaseSize;
+ }
+ memcpy(gEfiFdInfo.NvStoreDatabase, NvStoreDatabaseBuffer, NvStoreDatabaseSize);
+
+Done:
+ DestroyAllStorage (&mAllVarListEntry);
+ if (PreBinary != NULL) {
+ free (PreBinary);
+ }
+ if (Binary) {
+ free (Binary);
+ }
+ return Status;
+}
+
+extern UINT32 mMaxCount;
+extern UINT32 mCount;
+extern CHAR8 *mStringBuffer;
+
+/**
+ Read the HII configure file from all FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+ReadCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ UINT16 PreDefaultId;
+ UINT64 PrePlatformId;
+ LIST_ENTRY NewStorageListHead;
+ BOOLEAN BfvOverried;
+ FORMSET_STORAGE *Storage;
+ LIST_ENTRY *StorageLink;
+
+ Storage = NULL;
+ Status = EFI_SUCCESS;
+ BfvOverried = FALSE;
+ Index = 0;
+ PreDefaultId = 0xFFFF;
+ PrePlatformId = 0xFFFFFFFFFFFFFFFF;
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Read defaultId and platformId
+ //
+ if (!gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // If existed the variable data in BFV, abstract them to a variable list.
+ // If not exsited, just skip it.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadStorageFromNvStoreDatabase(&mBfvVarListEntry);
+ } else {
+ Status = ReadStorageFromBfv (&mBfvVarListEntry);
+ }
+ if (!EFI_ERROR (Status)) {
+ BfvOverried = TRUE;
+ }
+ }
+ //
+ // If not existed the storage data in BFV, evaluate the
+ // default value according to the defaultId and platformId
+ // Or else, skip it.
+ //
+ if (!BfvOverried) {
+ Status = EvaluateTheValueInFormset (FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Output the question and value information on screen
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Multi-platform mode support
+ //
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ StorageLink = GetFirstNode (&mBfvVarListEntry);
+ while (!IsNull (&mBfvVarListEntry, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ continue;
+ } else {
+ PreDefaultId = Storage->DefaultId[0];
+ PrePlatformId = Storage->PlatformId[0];
+ }
+ InitializeListHead(&NewStorageListHead);
+ //
+ // Use the varaible stroage list from BFV
+ //
+ Status = BuildVariableList(
+ &NewStorageListHead,
+ &mBfvVarListEntry,
+ Storage->DefaultId[0],
+ Storage->PlatformId[0],
+ FALSE,
+ READ
+ );
+
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ if (IsListEmpty (&NewStorageListHead)) {
+ continue;
+ }
+ Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ DestroyAllStorage (&NewStorageListHead);
+ StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+ }
+ } else {
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ InitializeListHead(&NewStorageListHead);
+ if (BfvOverried) {
+ //
+ // Use the varaible stroage list from BFV
+ //
+ Status = BuildVariableList(
+ &NewStorageListHead,
+ &mBfvVarListEntry,
+ mMultiPlatformParam.DefaultId[DefaultIndex],
+ mMultiPlatformParam.PlatformId[PlatformIndex],
+ FALSE,
+ READ
+ );
+ } else {
+ //
+ // Use the varaible storage list from IFR
+ //
+ Status = BuildVariableList(
+ &NewStorageListHead,
+ &mAllVarListEntry,
+ mMultiPlatformParam.DefaultId[DefaultIndex],
+ mMultiPlatformParam.PlatformId[PlatformIndex],
+ FALSE,
+ READ
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ if (IsListEmpty (&NewStorageListHead)) {
+ continue;
+ }
+ Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
+ if (EFI_ERROR (Status)) {
+ DestroyAllStorage (&NewStorageListHead);
+ return EFI_ABORTED;
+ }
+ DestroyAllStorage (&NewStorageListHead);
+ }
+ }
+ }
+ } else {
+ Status = PrintInfoInAllFormset (&mFormSetListEntry, &mAllVarListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Update the HII setup value.
+
+ Read the Config information from config file, and then compare it with the current FFS.
+ Record the different value to EFI variable.
+
+ @param Fv the Pointer to the FFS
+ @param Length the length of FFS
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+UpdateCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ BOOLEAN BfvOverried;
+
+ Status = EFI_SUCCESS;
+ BfvOverried = FALSE;
+ Index = 0;
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Read defaultId and platformId
+ //
+ if (!gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // If existed the variable data in BFV, abstract them to a variable list.
+ // If not exsited, just skip it.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = ReadStorageFromNvStoreDatabase (&mBfvVarListEntry);
+ } else {
+ Status = ReadStorageFromBfv (&mBfvVarListEntry);
+ }
+ if (!EFI_ERROR (Status)) {
+ BfvOverried = TRUE;
+ }
+ }
+ if (mMultiPlatformParam.MultiPlatformOrNot && BfvOverried) {
+ if (mUqiList == NULL) {
+ return EFI_SUCCESS;
+ }
+ Status = CheckValueUpdateList ();
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ } else {
+ //
+ // Evaluate the default value according to the defaultId and platformId
+ //
+ if (mUqiList == NULL) {
+ Status = EvaluateTheValueInFormset (FALSE);
+ } else {
+ Status = EvaluateTheValueInFormset (TRUE);
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // print error information in UQI list
+ //
+ if (PrintErrorInfo (mUqiList)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Output the variable information to BFV in multi-platform mode
+ // Or write it to the Nvstrage in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ if (ExistEfiVarOrNot (&mAllVarListEntry) && Operations == UPDATE) {
+ printf ("Error. Please use --remove or --ignore to update the variable storage for an FD with variables in its NvStorage.\n");
+ return EFI_ABORTED;
+ }
+ } else {
+ //
+ // Sync the data from List data to efi variable.
+ //
+ Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ printf ("Error. There is no available space in efi variable. \n");
+ return EFI_ABORTED;
+ }
+ if (Status == EFI_INVALID_PARAMETER) {
+ return EFI_ABORTED;
+ }
+ }
+
+ PrintUpdateListInfo (mUqiList);
+
+ return Status;
+}
+
+/**
+ Quick Update the HII setup value.
+
+ Read the Config information from command line directly, and then compare it with the current FFS.
+ Record the different value to EFI variable.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+
+EFI_STATUS
+QuickUpdateCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
+ return EFI_ABORTED;
+ }
+ //
+ // Check whether the FD has included the storage FFS
+ //
+ if (mMultiPlatformParam.ExistStorageFfsInBfv) {
+ printf ("Error. Variable storage exists in BFV of Fd. This is generated in multi-platform mode.\n");
+ printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
+ return EFI_ABORTED;
+ }
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Evaluate the default value according to the defaultId and platformId
+ //
+ Status = EvaluateTheValueInFormset (TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // print error information in UQI list
+ //
+ if (PrintErrorInfo (mUqiList)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Sync the data from mAllVarListEntry data to efi variable.
+ //
+ Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ printf ("Error. There is no available space in Nvstorage. \n");
+ return EFI_ABORTED;
+ }
+ if (Status == EFI_INVALID_PARAMETER) {
+ return EFI_ABORTED;
+ }
+
+ PrintUpdateListInfo (mUqiList);
+
+ return Status;
+}
+
+/**
+ Check the HII setup value.
+
+ Read the Config information from config file, and then compare it with the current FFS.
+ Print the different values on screen.
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+static
+EFI_STATUS
+CheckCongFile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT16 DefaultIndex;
+ UINT16 PlatformIndex;
+ UINT16 DefaultId;
+ UINT64 PlatformId;
+
+ Status = EFI_SUCCESS;
+ Index = 0;
+ DefaultIndex = 0;
+ PlatformIndex = 0;
+ DefaultId = 0;
+ PlatformId = 0;
+ //
+ // Read all Ifr information to Formset list
+ //
+ for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+ Status = ReadAllIfrToFromset (
+ gEfiFdInfo.FfsArray[Index],
+ gEfiFdInfo.Length[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Read defaultId and platformId
+ //
+ Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Read the config data from BFV in multi-platform mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ Status = ReadStorageFromBfv (&mAllVarListEntry);
+ if (EFI_ERROR (Status)) {
+ printf ("Error. No storage variable data exists in BFV.\n");
+ return EFI_ABORTED;
+ }
+ }
+
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ ScanUqiFullList (mUqiList);
+
+ //
+ // Multi-platform mode support
+ //
+ for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+ for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+ DefaultId = mMultiPlatformParam.DefaultId[DefaultIndex];
+ PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+ //
+ //Only parse one time, if a group of defaultId and platformId which have the same variable
+ // Take the first one as a key Id of a group
+ //
+ if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+ continue;
+ }
+
+ InitializeListHead(&mVarListEntry);
+ Status = BuildVariableList(
+ &mVarListEntry,
+ &mAllVarListEntry,
+ DefaultId,
+ PlatformId,
+ FALSE,
+ VERIFY
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ if (IsListEmpty (&mVarListEntry)) {
+ continue;
+ }
+ SetUqiParametersMultiMode (mUqiList, DefaultId, PlatformId);
+ DestroyAllStorage (&mVarListEntry);
+ }
+ }
+ } else {
+ //
+ // General mode
+ //
+ Status = ExtractDefault (
+ NULL,
+ NULL,
+ 0,
+ 0,
+ SystemLevel
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // If existed the variable in NvStorage, copy them to mVarListEntry.
+ // Synchronize the default value from the EFI variable zone to variable list
+ //
+ Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
+ if (Status == EFI_INVALID_PARAMETER) {
+ Status = EFI_ABORTED;
+ return Status;
+ }
+ //
+ // Update the value from script file
+ //
+ Status = SetUqiParameters (mUqiList,0, 0);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Copy Stroage from mVarListEntry to mAllVarListEntry
+ //
+ Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, VERIFY);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ }
+ PrintVerifiedListInfo (mUqiList);
+ return Status;
+}
+
+/**
+ Search the config file from the path list.
+
+ Split the path from env PATH, and then search the cofig
+ file from these paths. The priority is from left to
+ right of PATH string. When met the first Config file, it
+ will break and return the pointer to the full file name.
+
+ @param PathList the pointer to the path list.
+ @param FileName the pointer to the file name.
+
+ @retval The pointer to the file name.
+ @return NULL An error occurred.
+**/
+CHAR8 *
+SearchConfigFromPathList (
+ IN CHAR8 *PathList,
+ IN CHAR8 *FileName
+)
+{
+ CHAR8 *CurDir;
+ CHAR8 *FileNamePath;
+
+ CurDir = NULL;
+ FileNamePath = NULL;
+#ifndef __GNUC__
+ CurDir = strtok (PathList,";");
+#else
+ CurDir = strtok (PathList,":");
+#endif
+ while (CurDir != NULL) {
+ FileNamePath = (char *)calloc(
+ strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
+ sizeof(char)
+ );
+ if (FileNamePath == NULL) {
+ return NULL;
+ }
+ sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
+ if (access (FileNamePath, 0) != -1) {
+ return FileNamePath;
+ }
+#ifndef __GNUC__
+ CurDir = strtok(NULL, ";");
+#else
+ CurDir = strtok(NULL, ":");
+#endif
+ free (FileNamePath);
+ FileNamePath = NULL;
+ }
+ return NULL;
+}
+
+/**
+ FCE application entry point
+
+ @param argc The number of input parameters.
+ @param *argv[] The array pointer to the parameters.
+
+ @retval 0 The application exited normally.
+ @retval 1 An error occurred.
+ @retval 2 An error about check occurred.
+
+**/
+int
+main (
+ int argc,
+ char *argv[]
+ )
+{
+ EFI_STATUS Status;
+ FILE *OutputFd;
+ FILE *ScriptFile;
+ UINTN BytesWrite;
+ UINTN Index;
+ CHAR8 *TemDir;
+ BOOLEAN IsFileExist;
+ CHAR8 FullGuidToolDefinition[_MAX_PATH];
+ CHAR8 *PathList;
+ UINTN EnvLen;
+ CHAR8 *NewPathList;
+ UINTN FileNameIndex;
+ CHAR8 *InFilePath;
+ BOOLEAN UqiIsSet;
+
+ Status = EFI_SUCCESS;
+ OutputFd = NULL;
+ ScriptFile = NULL;
+ Operations = NONE;
+ BytesWrite = 0;
+ Index = 0;
+ TemDir = NULL;
+ mFormSetOrderRead = 0;
+ mFormSetOrderParse = 0;
+ IsFileExist = TRUE;
+ PathList = NULL;
+ NewPathList = NULL;
+ EnvLen = 0;
+ UqiIsSet = FALSE;
+
+ TemDir = getcwd (NULL, _MAX_PATH);
+ if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+ printf ("The directory is too long \n");
+ return FAIL;
+ }
+ strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+ strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+ memset (&mMultiPlatformParam, 0, sizeof (MULTI_PLATFORM_PARAMETERS));
+
+ SetUtilityName (UTILITY_NAME);
+ //
+ // Workaroud: the first call to this function
+ // returns a file name ends with dot
+ //
+#ifndef __GNUC__
+ tmpnam (NULL);
+#else
+ CHAR8 tmp[] = "/tmp/fileXXXXXX";
+ UINTN Fdtmp;
+ Fdtmp = mkstemp(tmp);
+ close(Fdtmp);
+#endif
+ //
+ // Save, and then skip filename arg
+ //
+ mUtilityFilename = argv[0];
+ argc--;
+ argv++;
+ //
+ // Get the same path with the application itself
+ //
+ if (strlen (mUtilityFilename) > _MAX_PATH - 1) {
+ Error (NULL, 0, 2000, "Parameter: The input file name is too long", NULL);
+ return FAIL;
+ }
+ strncpy (FullGuidToolDefinition, mUtilityFilename, _MAX_PATH - 1);
+ FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+ FileNameIndex = strlen (FullGuidToolDefinition);
+ while (FileNameIndex != 0) {
+ FileNameIndex --;
+ if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+ FullGuidToolDefinition[FileNameIndex] = 0;
+ strcpy (mFullGuidToolDefinitionDir, FullGuidToolDefinition);
+ break;
+ }
+ }
+ //
+ // Build the path list for Config file scan. The priority is below.
+ // 1. Scan the current path
+ // 2. Scan the same path with the application itself
+ // 3. Scan the current %PATH% of OS environment
+ // 4. Use the build-in default configuration
+ //
+ PathList = getenv("PATH");
+ if (PathList == NULL) {
+ Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
+ return FAIL;
+ }
+ EnvLen = strlen(PathList);
+ NewPathList = (char *)calloc(
+ strlen (".")
+ + strlen (";")
+ + strlen (mFullGuidToolDefinitionDir)
+ + strlen (";")
+ + EnvLen
+ + 1,
+ sizeof(char)
+ );
+ if (NewPathList == NULL) {
+ Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
+ PathList = NULL;
+ free (PathList);
+ return -1;
+ }
+#ifndef __GNUC__
+ sprintf (NewPathList, "%s;%s;%s", ".", mFullGuidToolDefinitionDir, PathList);
+#else
+ sprintf (NewPathList, "%s:%s:%s", ".", mFullGuidToolDefinitionDir, PathList);
+#endif
+
+ PathList = NULL;
+ free (PathList);
+
+ //
+ // Load Guid Tools definition
+ //
+ InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
+ free (NewPathList);
+ if (InFilePath != NULL) {
+ printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath);
+ mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+ free (InFilePath);
+ } else {
+ //
+ // Use the pre-defined standard guided tools.
+ //
+ printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n");
+ mParsedGuidedSectionTools = PreDefinedGuidedTools ();
+ }
+ //
+ // Parse the command line
+ //
+ strcpy (mSetupTxtName, "NoSetupFile");
+ Status = ParseCommmadLine (argc,argv);
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Print utility header
+ //
+ printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
+ UTILITY_NAME,
+ UTILITY_MAJOR_VERSION,
+ UTILITY_MINOR_VERSION,
+ __BUILD_VERSION
+ );
+ //
+ // Check the revision of BfmLib
+ //
+ Status = CheckBfmLibRevision ();
+ if (EFI_ERROR (Status)) {
+ printf ("Please use the correct revision of BfmLib %s. \n", __BUILD_VERSION);
+ return FAIL;
+ }
+ if (strcmp (mSetupTxtName, "NoSetupFile")) {
+ ScriptFile = fopen (mSetupTxtName, "r");
+ if (ScriptFile == NULL) {
+ printf ("Error. Cannot open the script file.\n");
+ return FAIL;
+ }
+ Status = PickUpUqiFromScript (ScriptFile);
+ if (EFI_ERROR (Status)) {
+ fclose (ScriptFile);
+ IsFileExist = FALSE;
+ goto Done;
+ }
+ fclose (ScriptFile);
+ }
+ if (!mMultiPlatformParam.MultiPlatformOrNot
+ && (Operations == UPDATE_REMOVE || Operations == UPDATE_IGNORE)
+ ) {
+ printf ("Error. --remove and --ignore cannot be used in normal mode.\n");
+ Status = FAIL;
+ goto Done;
+ }
+
+ if (access (TemDir, 0) != -1) {
+ LibRmDir (TemDir);
+ }
+
+ //
+ // Initialize the variables
+ //
+ Status = PickUpFfsFromFd ();
+ if (EFI_ERROR (Status)) {
+ printf ("Error. Invalid FD file.\n");
+ IsFileExist = FALSE;
+ Status = FAIL;
+ goto Done;
+ }
+ if (gEfiFdInfo.FfsArray[0] == NULL) {
+ printf ("Error. Cannot find any HII offset in current FD files, please check the BaseTools.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ //
+ //Config the global variables
+ //
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ UqiIsSet = TRUE;
+ }
+ Status = GetEfiVariablesAddr (UqiIsSet);
+ if (EFI_ERROR (Status)) {
+ printf ("Error. Cannot locate the EFI variable zone in FD.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ if (gEfiFdInfo.ExistNvStoreDatabase && !mMultiPlatformParam.MultiPlatformOrNot) {
+ mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+ }
+ //
+ // Initialize the FormSet and VarList List
+ //
+ InitializeListHead (&mFormSetListEntry);
+ InitializeListHead (&mVarListEntry);
+ InitializeListHead (&mBfvVarListEntry);
+ InitializeListHead (&mAllVarListEntry);
+
+ mStringBuffer = malloc (mMaxCount);
+ if (mStringBuffer == NULL) {
+ printf ("Fali to allocate memory!\n");
+ Status = FAIL;
+ goto Done;
+ }
+
+ //
+ // Decide how to deal with the Fd
+ //
+ switch (Operations) {
+
+ case READ:
+ printf ("\nStart the Read Mode:\n");
+ Status = ReadCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = FAIL;
+ }
+ break;
+
+ case UPDATE:
+ case UPDATE_REMOVE:
+ case UPDATE_IGNORE:
+ printf ("\nStart the Update Mode:\n");
+ Status = UpdateCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = FAIL;
+ }
+ break;
+
+ case VERIFY:
+ printf ("\nStart the Verify Mode:\n");
+ Status = CheckCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = VR_FAIL;
+ }
+ break;
+
+ case UPDATEQ:
+ printf ("\nStart the Update Quick Mode:\n");
+ Status = QuickUpdateCongFile ();
+ if (EFI_ERROR (Status)) {
+ Status = FAIL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (mCount > 0) {
+ mStringBuffer[mCount] = '\0';
+ fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
+ }
+ free (mStringBuffer);
+
+ if (Status != SUCCESS) {
+ goto Done;
+ }
+ //
+ // If multi-platform mode, insert the variables to BFV
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot
+ && (IsListEmpty (&mAllVarListEntry) == FALSE)
+ &&((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ))
+ ) {
+ IsFileExist = FALSE;
+ if (gEfiFdInfo.ExistNvStoreDatabase) {
+ Status = InsertBinaryToNvStoreDatabase (mInputFdName, mOutputFdName, &mAllVarListEntry);
+ } else {
+ Status = InsertBinaryToBfv (mInputFdName, mOutputFdName, &mAllVarListEntry);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Remove the variables in NvStorage in multi-platform mode by user specified requirement
+ //
+ if (Operations == UPDATE_REMOVE) {
+ if (gEfiFdInfo.Fd != NULL) {
+ free (gEfiFdInfo.Fd);
+ }
+ gEfiFdInfo.Fd = ReadFileToMemory (mOutputFdName, &gEfiFdInfo.FdSize);
+ if (gEfiFdInfo.Fd == NULL) {
+ Status = EFI_ABORTED;
+ } else {
+ Status = RemoveEfiVar (&mAllVarListEntry);
+ }
+ if (EFI_ERROR (Status)) {
+ printf ("Error. Failed to remove the variable from NVRAM.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ }
+ }
+
+ if (
+ (!mMultiPlatformParam.MultiPlatformOrNot &&((Operations == UPDATE) || (Operations == UPDATEQ)))
+ || (mMultiPlatformParam.MultiPlatformOrNot && (Operations == UPDATE_REMOVE || ((Operations == UPDATE) && IsListEmpty (&mAllVarListEntry))))
+ ) {
+ OutputFd = fopen (mOutputFdName, "wb+");
+ if (OutputFd == NULL) {
+ printf ("Error. Failed to create the output FD file.\n");
+ Status = FAIL;
+ goto Done;
+ }
+ fseek (OutputFd, 0, SEEK_SET);
+ BytesWrite = fwrite (gEfiFdInfo.Fd, sizeof (CHAR8), gEfiFdInfo.FdSize, OutputFd);
+ fclose (OutputFd);
+ if (BytesWrite != gEfiFdInfo.FdSize) {
+ printf ("Error. Failed to create the FD image. \n");
+ Status = FAIL;
+ goto Done;
+ }
+ }
+ if ((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ)) {
+ printf ("\nCongratulations. The output Fd file '%s' has been completed successfully.\n", mOutputFdName);
+ }
+Done:
+ //
+ // Delete the temporary directory and files
+ //
+ if (IsFileExist) {
+ LibRmDir (TemDir);
+ }
+ //
+ // Clean up
+ //
+ if (gEfiFdInfo.Fd != NULL) {
+ free (gEfiFdInfo.Fd);
+ }
+
+ if (mMultiPlatformParam.Uqi.Value != NULL) {
+ free (mMultiPlatformParam.Uqi.Value);
+ }
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ free (mMultiPlatformParam.Uqi.Data);
+ }
+ while (gEfiFdInfo.FfsArray[Index] != NULL) {
+ free (gEfiFdInfo.FfsArray[Index++]);
+ }
+
+ DestroyAllFormSet (&mFormSetListEntry);
+ DestroyAllStorage (&mVarListEntry);
+ DestroyAllStorage (&mBfvVarListEntry);
+ DestroyAllStorage (&mAllVarListEntry);
+ FreeUnidirectionList (mUqiList);
+
+ return Status;
+}
+
diff --git a/Platform/Intel/Tools/FCE/Fce.h b/Platform/Intel/Tools/FCE/Fce.h
new file mode 100644
index 0000000000..32cc3a1ccc
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Fce.h
@@ -0,0 +1,447 @@
+/** @file
+
+ FCE is a tool which enables developers to retrieve and change HII configuration ("Setup")
+ data in Firmware Device files (".fd" files).
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FCE_H_
+#define _FCE_H_ 1
+
+//#define NDEBUG
+
+#include "Common.h"
+#include "IfrParse.h"
+#include "VariableCommon.h"
+#include "BinaryParse.h"
+#include "BinaryCreate.h"
+///
+/// Utility global variables
+///
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 34
+
+#define UTILITY_NAME "FCE"
+
+#define SUCCESS 0
+#define FAIL 1
+#define VR_FAIL 2
+#define MAX_INPUT_ALLOCATE_SIZE 256
+
+///
+/// The type of file input and operations
+///
+typedef enum {
+ INFD,
+ OUTFD,
+ OUTTXT,
+ SETUPTXT
+} FILETYPE;
+
+typedef enum {
+ NONE,
+ READ,
+ UPDATE,
+ UPDATE_REMOVE,
+ UPDATE_IGNORE,
+ VERIFY,
+ UPDATEQ
+} OPERATION_TYPE;
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+ EFI_GUID Guid;
+ CHAR8* Name;
+ CHAR8* Path;
+ struct _GUID_SEC_TOOL_ENTRY *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+///
+/// The tag for use in identifying UNICODE files.
+/// If the file is UNICODE, the first 16 bits of the file will equal this value.
+///
+enum {
+ BigUnicodeFileTag = 0xFEFF,
+ LittleUnicodeFileTag = 0xFFFE
+};
+
+typedef enum {
+ ASCII,
+ BIG_UCS2,
+ LITTLE_UCS2
+} FILE_TYPE;
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+EFI_STATUS
+SynAuthEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the time stamp authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+
+EFI_STATUS
+SynAuthEfiVariableBasedTime (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariableBasedTime (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+**/
+
+EFI_STATUS
+SynEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveNormalEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Read all defaultId and platformId from binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+**/
+VOID
+ReadDefaultAndPlatformIdFromBfv (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+);
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+
+UINT32
+WriteDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+);
+
+/**
+ Store all defaultId and platformId to binary.
+
+ @param Binary The pointer to the bianry
+ @param Storage The pointer to the Storage
+
+ @retval Length Return the length of the header
+**/
+UINT32
+WriteNvStoreDefaultAndPlatformId (
+ IN UINT8 *Binary,
+ IN FORMSET_STORAGE *Storage
+);
+
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToNvStoreBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+
+UINT32
+ReadNvStoreVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Check whether exists the valid normal variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistNormalEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+
+VOID
+FixNvStoreVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+/**
+ Copy time-based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+ @return length The length of storage
+**/
+UINT32
+CopyTimeBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+/**
+ Read time-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadTimeBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Check whether exists the valid time-based variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistTimeBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Fix the size of time-based variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixBasedTimeVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+
+/**
+ Copy Monotonic-Based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyMonotonicBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ );
+
+/**
+ Read Monotonic-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadMonotonicBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ );
+
+/**
+ Check whether exists the valid MonotonicBased variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistMonotonicBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ );
+
+/**
+ Fix the size of montonic variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixMontonicVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ );
+
+/**
+ FCE application entry point
+
+ @param argc The number of input parameters.
+ @param *argv[] The array pointer to the parameters.
+
+ @retval 0 The application exited normally.
+ @retval 1 An error occurred.
+ @retval 2 An error about check occurred.
+
+**/
+int
+main (
+ int argc,
+ char *argv[]
+ );
+
+#endif
diff --git a/Platform/Intel/Tools/FCE/GNUmakefile b/Platform/Intel/Tools/FCE/GNUmakefile
new file mode 100644
index 0000000000..0ef0cb1c4b
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/GNUmakefile
@@ -0,0 +1,22 @@
+##@file
+#
+# GNU makefile for 'FCE' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+export ARCH
+export HOST_ARCH=$(ARCH)
+
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = FCE
+
+OBJECTS = Fce.o Variable.o TimeBasedVariable.o MonotonicBasedVariable.o IfrParse.o Common.o BinaryParse.o BinaryCreate.o Expression.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
+LIBS = -lCommon -lm
+
+
diff --git a/Platform/Intel/Tools/FCE/IfrParse.c b/Platform/Intel/Tools/FCE/IfrParse.c
new file mode 100644
index 0000000000..2f5a87baf3
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/IfrParse.c
@@ -0,0 +1,4836 @@
+/** @file
+
+ Parser for IFR binary encoding.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IfrParse.h"
+
+#ifndef EDKII_IFR_BIT_VARSTORE_GUID
+#define EDKII_IFR_BIT_VARSTORE_GUID \
+ {0x82DDD68B, 0x9163, 0x4187, {0x9B, 0x27, 0x20, 0xA8, 0xFD, 0x60 ,0xA7, 0x1D}}
+#endif
+
+#ifndef EDKII_IFR_NUMERIC_SIZE_BIT
+#define EDKII_IFR_NUMERIC_SIZE_BIT 0x3F
+#endif
+
+UINT16 mStatementIndex;
+UINT16 mExpressionOpCodeIndex;
+
+BOOLEAN mInScopeSubtitle;
+BOOLEAN mInScopeSuppress;
+BOOLEAN mInScopeGrayOut;
+BOOLEAN mInScopeDisable;
+FORM_EXPRESSION *mSuppressExpression;
+FORM_EXPRESSION *mGrayOutExpression;
+FORM_EXPRESSION *mDisableExpression;
+
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern LIST_ENTRY mVarListEntry;
+extern LIST_ENTRY mFormSetListEntry;
+extern UINT32 mFormSetOrderParse;
+
+#define FORM_SET_GUID_PREFIX "Form Set GUID: "
+#define EFI_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+
+UINT32 mMaxCount = 0x100000;
+UINT32 mCount = 0;
+CHAR8 *mStringBuffer = NULL;
+static EFI_GUID gEdkiiIfrBitVarGuid = EDKII_IFR_BIT_VARSTORE_GUID;
+
+/**
+ Produces a Null-terminated ASCII string in mStringBuffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ @param FormatString A null-terminated ASCII format string.
+ @param ... The variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+**/
+VOID
+StringPrint (
+ CHAR8 *FormatString,
+ ...
+)
+{
+ va_list Marker;
+ INT32 Count;
+
+ va_start (Marker, FormatString);
+ Count = vsprintf (mStringBuffer + mCount, FormatString, Marker);
+ mCount = mCount + Count;
+ va_end (Marker);
+ if (mCount + 0x400 > mMaxCount) {
+ mStringBuffer[mCount] = '\0';
+ fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
+ mCount = 0;
+ }
+}
+
+/**
+ Print the information of questions.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param Question The pointer to the question.
+ @param PrintOrNot Decide whether print or not.
+
+ @return NULL.
+
+**/
+static
+VOID
+PrintQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN BOOLEAN PrintOrNot
+ );
+
+/**
+ Writes a Unicode string specified by iStringToken and iLanguage to the script file (converted to ASCII).
+
+ @param Package A pointer to the Unicode string.
+
+ @return NULL
+
+**/
+static
+VOID
+LogUnicodeString (
+ IN CHAR16 *pcString
+ )
+{
+ UINTN Index;
+
+ if (pcString == NULL) {
+ return;
+ }
+ //
+ // replace the 0x0D to 0x20, because if the pcString has 0D 0A, then after print it,
+ // different editor may have different format
+ //
+ for (Index = 0; pcString[Index] != 0; Index++) {
+ if (pcString[Index] == 0x0D) {
+ pcString[Index] = 0x20;
+ }
+
+ StringPrint("%c", pcString[Index] & 0x00FF);
+ }
+}
+
+/**
+ Writes a UQIL Unicode string specified by iStringToken to the script file as an array of 16-bit integers in ASCII.
+
+ @param Package A pointer to the Unicode string.
+
+ @return NULL
+
+**/
+static
+VOID
+LogUqi (
+ IN CHAR16 *pcString
+ )
+{
+ UINT16 Index;
+ //
+ // Find the UNICODE string length (in CHAR16)
+ //
+ for (Index = 0; pcString[Index] != 0; Index++);
+ //
+ // Write each word as a hex integer
+ //
+ for (Index = 0; pcString[Index] != 0; Index++) {
+ StringPrint("%04X ", pcString[Index]);
+ }
+}
+
+/**
+ Get the question value with bit field from the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value get from.
+ @param Value Retun the value.
+
+**/
+VOID
+GetBitsQuestionValue(
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT8 *Buffer,
+ OUT UINT32 *Value
+ )
+{
+ UINT32 PreBits;
+ UINT32 Mask;
+
+ PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
+ Mask = (1<< Question->BitStorageWidth) -1;
+
+ *Value = *(UINT32*)Buffer;
+ (*Value) >>= PreBits;
+ (*Value) &= Mask;
+}
+
+/**
+ Set the question value with bit field to the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value set to.
+ @param Value The value need to set.
+
+**/
+VOID
+SetBitsQuestionValue (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN OUT UINT8 *Buffer,
+ IN UINT32 Value
+ )
+{
+ UINT32 PreBits;
+ UINT32 Mask;
+ UINT32 TmpValue;
+
+ PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
+ Value <<= PreBits;
+ Mask = (1<< Question->BitStorageWidth) -1;
+ Mask <<= PreBits;
+
+ TmpValue = *(UINT32*)(Buffer);
+ TmpValue = (TmpValue & (~Mask)) | Value;
+ CopyMem ((UINT32*)Buffer, &TmpValue, sizeof (UINT32));
+}
+
+/**
+ Print the current value of the specified question.
+
+ @param Question The pointer to question
+
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValue (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+ UINT32 Value;
+
+ VarBuffer = NULL;
+
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+
+ if (EFI_ERROR (Status)) {
+ StringPrint("\nCouldn't read current variable data.");
+ return EFI_ABORTED;
+ }
+ //
+ // Log the Value
+ //
+ if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->StorageWidth > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && !VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else {
+ if (Question->QuestionReferToBitField) {
+ GetBitsQuestionValue (Question, VarBuffer, &Value);
+ VarBuffer = (UINT8*)(&Value);
+ }
+ switch (Question->StorageWidth) {
+
+ case sizeof (UINT8):
+ StringPrint("%02X", (*(UINT8 *)VarBuffer) & 0xFF);
+ break;
+
+ case sizeof (UINT16):
+ StringPrint("%04X", (*(UINT16 *)VarBuffer) & 0xFFFF);
+ break;
+
+ case sizeof (UINT32):
+ StringPrint("%08X", (*(UINT32 *)VarBuffer) & 0xFFFFFFFF);
+ break;
+
+ case sizeof (UINT64):
+ StringPrint("%016llX", *((UINT64 *)VarBuffer));
+ break;
+
+ default:
+ StringPrint("0000 // Width > 16 is not supported -- FAILURE");
+ break;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the current value of the STRING question.
+
+ @param Question The pointer to question
+
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValueStr (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+
+ VarBuffer = NULL;
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+
+ if (EFI_ERROR (Status)) {
+ StringPrint("\nCouldn't read current variable data.");
+ return EFI_ABORTED;
+ }
+
+ //
+ // Log the Value
+ //
+ if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->VarStoreInfo.VarOffset > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->StorageWidth > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && !VarList->NewEfiVarstore
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else {
+ StringPrint("\"");
+ LogUnicodeString((CHAR16 *)VarBuffer);
+ StringPrint("\"");
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the current values of an Ordered List question.
+
+ @param Question The pointer to question
+ @param MaxEntries The max number of options
+ @param VarList The dual pointer to the Node of VarList
+
+ @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValueList (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 CurrentEntry;
+ UINT8 *VarBuffer;
+
+ CurrentEntry = 0;
+ VarBuffer = NULL;
+
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+
+ if (EFI_ERROR (Status)) {
+ StringPrint("\nCouldn't read current variable data.");
+ return EFI_ABORTED;
+ }
+ //
+ // Log the value
+ //
+ if (
+ ((Question->VarStoreInfo.VarOffset + Question->MaxContainers) > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else if (
+ (Question->MaxContainers > VarList->Size) \
+ && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)
+ ) {
+ StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+ } else {
+ for (CurrentEntry = 0; CurrentEntry < Question->MaxContainers; CurrentEntry++) {
+
+ switch (Question->StorageWidth/Question->MaxContainers){
+
+ case 1:
+ StringPrint("%02X ", VarBuffer[CurrentEntry]);
+ break;
+
+ case 2:
+ StringPrint("%04X ", *((UINT16 *)VarBuffer + CurrentEntry));
+ break;
+
+ case 4:
+ StringPrint("%08X ", *((UINT32 *)VarBuffer + CurrentEntry));
+ break;
+
+ case 8:
+ StringPrint("%016llX ", *((UINT64 *)VarBuffer + CurrentEntry));
+ break;
+
+ default:
+ StringPrint("%02X ", VarBuffer[CurrentEntry]);
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Compare two Uqi parameters
+
+ @param UqiParm1 The pointer to the first Uqi parameter.
+ @param UqiParm2 The pointer to the second Uqi parameter.
+
+ @retval TRUE If these two Uqi parameters are the same, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+BOOLEAN
+CompareUqiHeader (
+ IN CONST UQI_HEADER *UqiParm1,
+ IN CONST UQI_HEADER *UqiParm2
+ )
+{
+ INT32 Index;
+
+ if (UqiParm1->HexNum != UqiParm2->HexNum) {
+ return FALSE;
+ }
+
+ for (Index = UqiParm1->HexNum - 1; Index >= 0; Index--) {
+ if (UqiParm1->Data[Index] != UqiParm2->Data[Index]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Check whether existed a same variable in the LIST_ENTRY.
+
+ @param CurVarList A pointer to a variable node.
+
+ @return Pointer If existed the same variable, return the pointer to the Node.
+ @return NULL Otherwise, return FALSE
+
+**/
+static
+FORMSET_STORAGE *
+NotSameVariableInVarList (
+ IN LIST_ENTRY *VariableListEntry,
+ IN FORMSET_STORAGE *StorageNode
+ )
+{
+ FORMSET_STORAGE *CurNode;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *StorageListHead;
+
+ StorageListHead = VariableListEntry;
+ CurNode = NULL;
+
+ //
+ // Find Storage for this Question
+ //
+ Link = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, Link)) {
+ CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if (!CompareGuid (&StorageNode->Guid, &CurNode->Guid) \
+ && (CurNode->Name != NULL) \
+ && (StorageNode->Name != NULL) \
+ && !FceStrCmp (StorageNode->Name, CurNode->Name) \
+ && (StorageNode - CurNode != 0)
+ ) {
+ //
+ // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+ // two variables with same guid same name, but different type, we will take as the same
+ // in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == StorageNode->Type)) {
+ //
+ // If matched, get the address of EFI_IFR_VARSTORE data.
+ //
+ return CurNode;
+ break;
+ } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ return CurNode;
+ break;
+ }
+ }
+ Link = GetNextNode (StorageListHead, Link);
+ }
+ return NULL;
+}
+
+/**
+ Get the UniString by the offset.
+
+ @param UniPackge A pointer to the beginning of Null-terminated Unicode string Array.
+ @param CurUniPackge A pointer to the current position of Null-terminated Unicode string Array.
+ @param VarDefaultNameId The string ID.
+ @param CurOrDefaultLang Use the current language or the default language.
+ @param VarDefaultName return the name string.
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER
+ @return EFI_NOT_FOUND
+**/
+static
+EFI_STATUS
+GetStringByOffset (
+ IN UINT8 *UniPackge,
+ IN UINT8 *CurUniPackge,
+ IN UINT16 VarDefaultNameId,
+ IN BOOLEAN CurOrDefaultLang,
+ IN OUT CHAR16 **VarDefaultName
+ )
+{
+ UINT8 *HiiStringHeader;
+ UINT32 Offset;
+ UINT32 Count;
+ UINT32 Index;
+ EFI_HII_STRING_BLOCK *Block;
+ VOID *ThisBlock;
+
+ assert ((UniPackge != NULL) && (CurUniPackge != NULL));
+
+ HiiStringHeader = NULL;
+ Offset = 1;
+ Count = 0;
+ Block = NULL;
+ ThisBlock = NULL;
+
+ if (VarDefaultNameId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (CurOrDefaultLang) {
+ HiiStringHeader = CurUniPackge;
+ } else {
+ HiiStringHeader = UniPackge + 4;
+ }
+
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)HiiStringHeader + ((EFI_HII_STRING_PACKAGE_HDR *)HiiStringHeader)->HdrSize);
+ //
+ // Search the matched String in specificated language package by the Offset
+ //
+ while( Block->BlockType != EFI_HII_SIBT_END ) {
+ switch (Block->BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index + 1];
+ break;
+
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)(((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock) + 1);
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ ThisBlock = (VOID *)Block;
+ for( Count= ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
+ for ( ; ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ }
+ Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ ThisBlock = (VOID *)Block;
+ for( Count = ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) ;
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ ThisBlock = (VOID *)Block;
+ if (Offset == VarDefaultNameId) {
+ *VarDefaultName = malloc ((FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16));
+ if (*VarDefaultName == NULL) {
+ printf ("Fail to allocate memory");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset (
+ *VarDefaultName,
+ 0,
+ (FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16)
+ );
+ StrCpy (
+ *VarDefaultName,
+ (CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText
+ );
+ return EFI_SUCCESS;
+ }
+
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText[Index + 1];
+ Offset += 1;
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index + 1];
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ ThisBlock = (VOID *)Block;
+ for( Count = ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
+ for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ }
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ ThisBlock = (VOID *)Block;
+ for( Count= ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringCount, Index = 0 ; Count ; Count--, Index++ ) {
+ for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+ }
+ Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *)ThisBlock)->StringText[Index];
+ break;
+
+ case EFI_HII_SIBT_DUPLICATE:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_DUPLICATE_BLOCK *) ThisBlock + 1);
+ break;
+
+ case EFI_HII_SIBT_SKIP2:
+ ThisBlock = (VOID *)Block;
+ Offset += ((EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock)->SkipCount;
+ Block = (EFI_HII_STRING_BLOCK *)( (EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock + 1);
+ break;
+
+ case EFI_HII_SIBT_SKIP1:
+ ThisBlock = (VOID *)Block;
+ Offset += ((EFI_HII_SIBT_SKIP1_BLOCK *) ThisBlock)->SkipCount;
+ Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_SKIP1_BLOCK *)ThisBlock + 1);
+ break;
+
+ case EFI_HII_SIBT_EXT1:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT1_BLOCK *) ThisBlock)->Length);
+ break;
+
+ case EFI_HII_SIBT_EXT2:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT2_BLOCK *) ThisBlock)->Length);
+ break;
+
+ case EFI_HII_SIBT_EXT4:
+ ThisBlock = (VOID *)Block;
+ Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT4_BLOCK *)ThisBlock)->Length);
+ break;
+
+ case EFI_HII_SIBT_FONT:
+ ThisBlock = (VOID *)Block;
+ for (Index = 0 ; ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index] != 0 ; Index++) ;
+ Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index + 1];
+ break;
+
+ default:
+ StringPrint("Unhandled type = 0x%x\n", Block->BlockType);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Parse the UniString to get the string information.
+
+ @param CachedStringList A pointer to cached string list
+ @param UniPackge A pointer to a Null-terminated Unicode string Array.
+ @param VarDefaultNameId The string ID.
+ @param Language The language, en-US UQI or eng.
+ @param VarDefaultName return the name string.
+
+ @return EFI_SUCCESS If get the name string successfully
+ @return EFI_NOT_FOUND An error occurred.
+ @return EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+FindDefaultName (
+ IN FORMSET_STRING_LIST *CachedStringList,
+ IN UINT8 *UniPackge,
+ IN UINT16 VarDefaultNameId,
+ IN LANGUAGE Language,
+ IN OUT CHAR16 **VarDefaultName
+ )
+{
+ CHAR8 *UniPackgeEnd;
+ CHAR8 *UniBin;
+ CHAR8 LangStr[10];
+ BOOLEAN IsFound;
+ EFI_STATUS Status;
+ EFI_STRING_ID Index;
+ STRING_INFO *TempBuffer;
+
+ UniBin = NULL;
+ IsFound = FALSE;
+ Status = EFI_NOT_FOUND;
+
+ UniBin = (CHAR8 *) UniPackge + 4;
+ UniPackgeEnd = (CHAR8 *) UniPackge + *(UINT32 *)UniPackge;
+
+ //
+ //Handle with the invalid usage "STRING_TOKEN(0)"
+ //
+ if (VarDefaultNameId == 0) {
+ *VarDefaultName = L"";
+ return EFI_SUCCESS;
+ }
+
+ if (CachedStringList != NULL) {
+ for (Index = 0; Index < CachedStringList->CachedIdNum; Index ++) {
+ if (VarDefaultNameId == CachedStringList->StringInfoList[Index].StringId) {
+ *VarDefaultName = CachedStringList->StringInfoList[Index].String;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ switch (Language) {
+
+ case UQI:
+ strcpy (LangStr, "uqi");
+ break;
+
+ case EN_US:
+ strcpy (LangStr, "en-US");
+ break;
+
+ case ENG:
+ strcpy (LangStr, "eng");
+ break;
+
+ default:
+ strcpy (LangStr, "en-US");
+ break;
+ }
+ IsFound = FALSE;
+
+ if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ //
+ // Search the specified language package
+ //
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, LangStr) == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ //
+ //If not find the string ID, use the en eng or en-US instead.
+ //
+ if (!IsFound) {
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if ((strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0) \
+ || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) \
+ || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0) \
+ ) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ }
+ //
+ //If not still find the string ID, use the first one instead.
+ //
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ //If not find the specified string in UQI package, we use the en en-us eng or uqi insteadly
+ //
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ IsFound = FALSE;
+ UniBin = (CHAR8 *) UniPackge + 4;
+
+ while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi") == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ Status = GetStringByOffset (
+ UniPackge,
+ (UINT8 *)UniBin,
+ VarDefaultNameId,
+ IsFound,
+ VarDefaultName
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ *VarDefaultName = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ if (CachedStringList != NULL) {
+ if (CachedStringList->CachedIdNum >= CachedStringList->MaxIdNum) {
+ TempBuffer = calloc (sizeof (STRING_INFO), CachedStringList->MaxIdNum + STRING_NUMBER);
+ if (TempBuffer == NULL) {
+ printf ("Fail to allocate memory! \n");
+ free (*VarDefaultName);
+ *VarDefaultName = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (TempBuffer, CachedStringList->StringInfoList, sizeof (STRING_INFO) * CachedStringList->MaxIdNum);
+ FreePool (CachedStringList->StringInfoList);
+ CachedStringList->StringInfoList = TempBuffer;
+ CachedStringList->MaxIdNum = CachedStringList->MaxIdNum + STRING_NUMBER;
+ }
+ CachedStringList->StringInfoList[CachedStringList->CachedIdNum].StringId = VarDefaultNameId;
+ CachedStringList->StringInfoList[CachedStringList->CachedIdNum].String = *VarDefaultName;
+ CachedStringList->CachedIdNum ++;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the variable Guid and Name by the variableId and FormSetOrder.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param ListEntry The pointer to the LIST_ENTRY.
+
+ @return EFI_SUCCESS
+ @return EFI_NOT_FOUND If not find the the variable, or the variable doesn't belong to EfiVarStore or VarStore.
+**/
+static
+EFI_STATUS
+GetGuidNameByVariableId (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_STATEMENT *Question,
+ IN LIST_ENTRY *ListEntry
+ )
+{
+ FORMSET_STORAGE *CurNode;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *StorageListHead;
+ EFI_STATUS Status;
+ CHAR16 *EfiVariableName;
+
+ StorageListHead = ListEntry;
+ CurNode = NULL;
+ Status = EFI_SUCCESS;
+ EfiVariableName = NULL;
+
+ Link = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, Link)) {
+ CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if ((FormSet->FormSetOrder == CurNode->FormSetOrder) \
+ && (Question->VarStoreId == CurNode->VarStoreId)
+ ) {
+ //
+ // Copy type to question to avoid the case that EfiVarStore and VarStore have the same Guid and name.
+ //
+ Question->Type = CurNode->Type;
+ Question->NewEfiVarstore = CurNode->NewEfiVarstore;
+ Question->Attributes = CurNode->Attributes;
+
+ if (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP) {
+ CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
+ //
+ // If the first time to access the old EfiVarStore, need to sync the variable name
+ //
+ if (!CurNode->NewEfiVarstore) {
+ if (CurNode->Buffer == NULL) {
+ CurNode->Buffer = malloc (Question->StorageWidth);
+ }
+ if (CurNode->Name == NULL) {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->VarStoreInfo.VarName,
+ EN_US,
+ &EfiVariableName
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ CurNode->Name = EfiVariableName;
+ }
+ if (CurNode->Size == 0) {
+ CurNode->Size = Question->StorageWidth;
+ }
+ }
+ //
+ // Check whether the Efivariable variable name is valid.
+ //
+ if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
+ StringPrint ("Error. The variable name of question is NULL. Its UQI is: ");
+ StringPrint("Q %04X ", Question->Uqi.HexNum);
+ LogUqi (Question->Uqi.Data);
+ StringPrint ("\n");
+ return EFI_ABORTED;
+ }
+ if (Question->VariableName == NULL) {
+ Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
+ if (Question->VariableName == NULL) {
+ return EFI_ABORTED;
+ }
+ }
+ StrCpy (Question->VariableName, CurNode->Name);
+
+ return EFI_SUCCESS;
+
+ } else if (CurNode->Type == EFI_IFR_VARSTORE_OP) {
+ CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
+ if (Question->VariableName == NULL) {
+ Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
+ if (Question->VariableName == NULL) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Check whether the variable variable name is valid.
+ //
+ if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
+ StringPrint ("Error. The variable name of question is NULL. UQI:");
+ StringPrint("Q %04X ", Question->Uqi.HexNum);
+ LogUqi (Question->Uqi.Data);
+ StringPrint ("\n");
+ return EFI_ABORTED;
+ }
+ StrCpy (Question->VariableName, CurNode->Name);
+ return EFI_SUCCESS;
+ }
+ }
+ Link = GetNextNode (StorageListHead, Link);
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Search the variable list according to the variable Guid and name, and return the pointer
+ of that Node.
+
+ @param HiiObjList The pointer to the Question
+ @param VarName The EFI variable name need to be updated to VarList
+ @param Offset The offset of the variable
+ @param StorageListHead The pointer to the LIST_ENTRY of Storage
+ @param Vaue The value in that value offset of the variable
+ @param VarList The dual pointer of Varlist
+
+ @return EFI_SUCCESS
+ @return EFI_NOT_FOUND
+**/
+EFI_STATUS
+SearchVarStorage (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16* VarName,
+ IN UINT32 Offset,
+ IN LIST_ENTRY *StorageListHead,
+ IN OUT CHAR8 **Value,
+ IN OUT FORMSET_STORAGE **VarList
+ )
+{
+ FORMSET_STORAGE *CurNode;
+ LIST_ENTRY *Link;
+ BOOLEAN FindOrNot;
+
+ CurNode = NULL;
+ FindOrNot = FALSE;
+ *VarList = NULL;
+ //
+ // Find Storage for this Question
+ //
+ Link = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, Link)) {
+ CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+ //
+ // Deal with the old EfiVarstore before UEFI2.31
+ //
+ if (!CompareGuid (&Question->Guid, &CurNode->Guid) \
+ && (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP) \
+ && !CurNode->NewEfiVarstore \
+ && (Question->VariableName != NULL) \
+ && (CurNode->Name != NULL) \
+ && !FceStrCmp(Question->VariableName, CurNode->Name)
+ ) {
+ //
+ // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+ // two variables with same guid same name, but different type, we will take as the same
+ // in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
+ //
+ // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
+ //
+ *Value = (CHAR8 *)CurNode->Buffer;
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
+ //
+ *Value = (CHAR8 *)CurNode->Buffer;
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ }
+ }
+
+ if (!CompareGuid (&Question->Guid, &CurNode->Guid) \
+ && (CurNode->Name != NULL) \
+ && (Question->VariableName != NULL) \
+ && !FceStrCmp(Question->VariableName, CurNode->Name)
+ ) {
+ //
+ // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+ // two variables with same guid same name, but different type, we will take as the same
+ // in general mode
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
+ //
+ // If matched, get the address of EFI_IFR_VARSTORE data.
+ //
+ *Value = (CHAR8 *)(CurNode->Buffer + Offset);
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // If matched, get the address of EFI_IFR_VARSTORE data.
+ //
+ *Value = (CHAR8 *)(CurNode->Buffer + Offset);
+ *VarList = CurNode;
+ FindOrNot = TRUE;
+ break;
+ }
+ }
+ Link = GetNextNode (StorageListHead, Link);
+ }
+ if (!FindOrNot) {
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN UINT8 *UniPackge
+ )
+{
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (UniPackge == NULL) {
+ return NULL;
+ }
+
+ Status = FindDefaultName (
+ NULL,
+ UniPackge,
+ Token,
+ EN_US,
+ &VarDefaultName
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return VarDefaultName;
+}
+
+/**
+ Initialize Statement header members.
+
+ @param OpCodeData Pointer of the raw OpCode data.
+ @param FormSet Pointer of the current FormSe.
+ @param Form Pointer of the current Form.
+
+ @return The Statement.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateStatement (
+ IN UINT8 *OpCodeData,
+ IN OUT FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ EFI_IFR_STATEMENT_HEADER *StatementHdr;
+
+ if (Form == NULL) {
+ //
+ // We are currently not in a Form Scope, so just skip this Statement
+ //
+ return NULL;
+ }
+
+ Statement = &FormSet->StatementBuffer[mStatementIndex];
+ mStatementIndex++;
+
+ InitializeListHead (&Statement->DefaultListHead);
+ InitializeListHead (&Statement->OptionListHead);
+ InitializeListHead (&Statement->InconsistentListHead);
+ InitializeListHead (&Statement->NoSubmitListHead);
+ InitializeListHead (&Statement->WarningListHead);
+
+ Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE;
+
+ Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+ Statement->QuestionReferToBitField = FALSE;
+
+ StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID));
+ CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID));
+
+ if (mInScopeSuppress) {
+ Statement->SuppressExpression = mSuppressExpression;
+ }
+
+ if (mInScopeGrayOut) {
+ Statement->GrayOutExpression = mGrayOutExpression;
+ }
+
+
+ if (mInScopeDisable) {
+ Statement->DisableExpression = mDisableExpression;
+ }
+
+ Statement->InSubtitle = mInScopeSubtitle;
+
+ //
+ // Insert this Statement into current Form
+ //
+ InsertTailList (&Form->StatementListHead, &Statement->Link);
+
+ return Statement;
+}
+
+/**
+ Initialize Question's members.
+
+ @param OpCodeData Pointer of the raw OpCode data.
+ @param FormSet Pointer of the current FormSet.
+ @param Form Pointer of the current Form.
+
+ @return The Question.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateQuestion (
+ IN UINT8 *OpCodeData,
+ IN OUT FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_BROWSER_STATEMENT *Statement;
+ EFI_IFR_QUESTION_HEADER *QuestionHdr;
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ NAME_VALUE_NODE *NameValueNode;
+
+ Statement = CreateStatement (OpCodeData, FormSet, Form);
+ if (Statement == NULL) {
+ return NULL;
+ }
+
+ QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+ CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID));
+ CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16));
+
+ Statement->QuestionFlags = QuestionHdr->Flags;
+
+ Statement->FormSetOrder = mFormSetOrderParse;
+
+ if (Statement->VarStoreId == 0) {
+ //
+ // VarStoreId of zero indicates no variable storage
+ //
+ return Statement;
+ }
+
+ //
+ // Find Storage for this Question
+ //
+ Link = GetFirstNode (FormSet->StorageListHead);
+ while (!IsNull (FormSet->StorageListHead, Link)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+
+ if ((Storage->VarStoreId == Statement->VarStoreId)
+ && (Storage->FormSetOrder == Statement->FormSetOrder)) {
+ Statement->Storage = Storage;
+ break;
+ }
+
+ Link = GetNextNode (FormSet->StorageListHead, Link);
+ }
+ ASSERT (Statement->Storage != NULL);
+
+ if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+ Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->UnicodeBinary);
+ ASSERT (Statement->VariableName != NULL);
+ //
+ // Insert to Name/Value varstore list
+ //
+ NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE));
+ ASSERT (NameValueNode != NULL);
+ NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE;
+ NameValueNode->Name = FceAllocateCopyPool (FceStrSize (Statement->VariableName), Statement->VariableName);
+ ASSERT (NameValueNode->Name != NULL);
+ NameValueNode->Value = AllocateZeroPool (0x10);
+ ASSERT (NameValueNode->Value != NULL);
+ NameValueNode->EditValue = AllocateZeroPool (0x10);
+ ASSERT (NameValueNode->EditValue != NULL);
+
+ InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link);
+ }
+
+ return Statement;
+}
+
+
+/**
+ Allocate a FORM_EXPRESSION node.
+
+ @param Form The Form associated with this Expression
+
+ @return Pointer to a FORM_EXPRESSION data structure.
+
+**/
+FORM_EXPRESSION *
+CreateExpression (
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ FORM_EXPRESSION *Expression;
+
+ Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+ ASSERT (Expression != NULL);
+ Expression->Signature = FORM_EXPRESSION_SIGNATURE;
+ InitializeListHead (&Expression->OpCodeListHead);
+
+ return Expression;
+}
+
+
+/**
+ Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List.
+
+ @param FormSet Pointer of the current FormSet
+
+ @return Pointer to a FORMSET_STORAGE data structure.
+
+**/
+FORMSET_STORAGE *
+CreateStorage (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ FORMSET_STORAGE *Storage;
+
+ Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE));
+ ASSERT (Storage != NULL);
+ Storage->Signature = FORMSET_STORAGE_SIGNATURE;
+ InitializeListHead (&Storage->NameValueListHead);
+ InsertTailList (FormSet->StorageListHead, &Storage->Link);
+
+ return Storage;
+}
+
+/**
+ Free resources of a Expression.
+
+ @param FormSet Pointer of the Expression
+
+**/
+VOID
+DestroyExpression (
+ IN FORM_EXPRESSION *Expression
+ )
+{
+ LIST_ENTRY *Link;
+ EXPRESSION_OPCODE *OpCode;
+ LIST_ENTRY *SubExpressionLink;
+ FORM_EXPRESSION *SubExpression;
+
+ while (!IsListEmpty (&Expression->OpCodeListHead)) {
+ Link = GetFirstNode (&Expression->OpCodeListHead);
+ OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+ RemoveEntryList (&OpCode->Link);
+
+ if (OpCode->ValueList != NULL) {
+ FreePool (OpCode->ValueList);
+ }
+
+ if (OpCode->ValueName != NULL) {
+ FreePool (OpCode->ValueName);
+ }
+
+ if (OpCode->MapExpressionList.ForwardLink != NULL) {
+ while (!IsListEmpty (&OpCode->MapExpressionList)) {
+ SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+ SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+ RemoveEntryList(&SubExpression->Link);
+ DestroyExpression (SubExpression);
+ }
+ }
+ }
+
+ //
+ // Free this Expression
+ //
+ FreePool (Expression);
+}
+
+
+/**
+ Free resources of a storage.
+
+ @param Storage Pointer of the storage
+
+**/
+VOID
+DestroyStorage (
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ LIST_ENTRY *Link;
+ NAME_VALUE_NODE *NameValueNode;
+
+ if (Storage == NULL) {
+ return;
+ }
+
+ if (Storage->Name != NULL) {
+ FreePool (Storage->Name);
+ }
+ if (Storage->Buffer != NULL) {
+ FreePool (Storage->Buffer);
+ }
+
+ while (!IsListEmpty (&Storage->NameValueListHead)) {
+ Link = GetFirstNode (&Storage->NameValueListHead);
+ NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link);
+ RemoveEntryList (&NameValueNode->Link);
+
+ if (NameValueNode->Name != NULL) {
+ FreePool (NameValueNode->Name);
+ }
+ if (NameValueNode->Value != NULL) {
+ FreePool (NameValueNode->Value);
+ }
+ if (NameValueNode->EditValue != NULL) {
+ FreePool (NameValueNode->EditValue);
+ }
+ FreePool (NameValueNode);
+ }
+
+ FreePool (Storage);
+ Storage = NULL;
+}
+
+/**
+ Free resources allocated for all Storage in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllStorage (
+ IN LIST_ENTRY *StorageEntryListHead
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *Storage;
+ //
+ // Parse Fromset one by one
+ //
+ if (StorageEntryListHead->ForwardLink != NULL) {
+ while (!IsListEmpty (StorageEntryListHead)) {
+ Link = GetFirstNode (StorageEntryListHead);
+ Storage = FORMSET_STORAGE_FROM_LINK (Link);
+ RemoveEntryList (&Storage->Link);
+
+ DestroyStorage (Storage);
+ }
+ }
+ StorageEntryListHead = NULL;
+}
+
+/**
+ Free resources of a Statement.
+
+ @param FormSet Pointer of the FormSet
+ @param Statement Pointer of the Statement
+
+**/
+VOID
+DestroyStatement (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_STATEMENT *Statement
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_DEFAULT *Default;
+ QUESTION_OPTION *Option;
+ FORM_EXPRESSION *Expression;
+
+ //
+ // Free Default value List
+ //
+ while (!IsListEmpty (&Statement->DefaultListHead)) {
+ Link = GetFirstNode (&Statement->DefaultListHead);
+ Default = QUESTION_DEFAULT_FROM_LINK (Link);
+ RemoveEntryList (&Default->Link);
+
+ if (Default->Value.Buffer != NULL) {
+ FreePool(Default->Value.Buffer);
+ }
+ FreePool (Default);
+ }
+
+ //
+ // Free Options List
+ //
+ while (!IsListEmpty (&Statement->OptionListHead)) {
+ Link = GetFirstNode (&Statement->OptionListHead);
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ RemoveEntryList (&Option->Link);
+
+ FreePool (Option);
+ }
+
+ //
+ // Free Inconsistent List
+ //
+ while (!IsListEmpty (&Statement->InconsistentListHead)) {
+ Link = GetFirstNode (&Statement->InconsistentListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free NoSubmit List
+ //
+ while (!IsListEmpty (&Statement->NoSubmitListHead)) {
+ Link = GetFirstNode (&Statement->NoSubmitListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free WarningIf List
+ //
+ while (!IsListEmpty (&Statement->WarningListHead)) {
+ Link = GetFirstNode (&Statement->WarningListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+ if (Statement->VariableName != NULL) {
+ FreePool (Statement->VariableName);
+ }
+ if (Statement->BufferValue != NULL) {
+ FreePool (Statement->BufferValue);
+ }
+}
+
+/**
+ Free resources of a Form.
+
+ @param FormSet Pointer of the FormSet
+ @param Form Pointer of the Form.
+
+**/
+VOID
+DestroyForm (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT FORM_BROWSER_FORM *Form
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_EXPRESSION *Expression;
+ FORM_BROWSER_STATEMENT *Statement;
+
+ //
+ // Free Form Expressions
+ //
+ while (!IsListEmpty (&Form->ExpressionListHead)) {
+ Link = GetFirstNode (&Form->ExpressionListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free Statements/Questions
+ //
+ while (!IsListEmpty (&Form->StatementListHead)) {
+ Link = GetFirstNode (&Form->StatementListHead);
+ Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ RemoveEntryList (&Statement->Link);
+
+ DestroyStatement (FormSet, Statement);
+ }
+
+ //
+ // Free this Form
+ //
+ FreePool (Form);
+}
+
+
+/**
+ Free resources allocated for a FormSet.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ LIST_ENTRY *Link;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ FORM_EXPRESSION *Expression;
+ FORM_BROWSER_FORM *Form;
+ UINT16 Index;
+
+ //
+ // Free FormSet Default Store
+ //
+ if (FormSet->DefaultStoreListHead.ForwardLink != NULL) {
+ while (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+ Link = GetFirstNode (&FormSet->DefaultStoreListHead);
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link);
+ RemoveEntryList (&DefaultStore->Link);
+
+ FreePool (DefaultStore);
+ }
+ }
+
+ //
+ // Free Formset Expressions
+ //
+ while (!IsListEmpty (&FormSet->ExpressionListHead)) {
+ Link = GetFirstNode (&FormSet->ExpressionListHead);
+ Expression = FORM_EXPRESSION_FROM_LINK (Link);
+ RemoveEntryList (&Expression->Link);
+
+ DestroyExpression (Expression);
+ }
+
+ //
+ // Free Forms
+ //
+ if (FormSet->FormListHead.ForwardLink != NULL) {
+ while (!IsListEmpty (&FormSet->FormListHead)) {
+ Link = GetFirstNode (&FormSet->FormListHead);
+ Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+ RemoveEntryList (&Form->Link);
+
+ DestroyForm (FormSet, Form);
+ }
+ }
+
+ if (FormSet->StatementBuffer != NULL) {
+ FreePool (FormSet->StatementBuffer);
+ }
+ if (FormSet->ExpressionBuffer != NULL) {
+ FreePool (FormSet->ExpressionBuffer);
+ }
+ if (FormSet->EnUsStringList.StringInfoList != NULL) {
+ for (Index = 0; Index < FormSet->EnUsStringList.CachedIdNum; Index ++) {
+ FreePool (FormSet->EnUsStringList.StringInfoList[Index].String);
+ }
+ FreePool (FormSet->EnUsStringList.StringInfoList);
+ }
+ if (FormSet->UqiStringList.StringInfoList != NULL) {
+ for (Index = 0; Index < FormSet->UqiStringList.CachedIdNum; Index ++) {
+ FreePool (FormSet->UqiStringList.StringInfoList[Index].String);
+ }
+ FreePool (FormSet->UqiStringList.StringInfoList);
+ }
+
+ FreePool (FormSet);
+}
+
+/**
+ Free resources allocated for all FormSet in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllFormSet (
+ IN LIST_ENTRY *FormSetEntryListHead
+ )
+{
+ LIST_ENTRY *Link;
+ FORM_BROWSER_FORMSET *FormSet;
+ //
+ // Parse Fromset one by one
+ //
+ if (FormSetEntryListHead->ForwardLink != NULL) {
+ while (!IsListEmpty (FormSetEntryListHead)) {
+ Link = GetFirstNode (FormSetEntryListHead);
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+ RemoveEntryList (&FormSet->Link);
+ DestroyFormSet (FormSet);
+ }
+ }
+}
+
+/**
+ Tell whether this Operand is an Expression OpCode or not
+
+ @param Operand Operand of an IFR OpCode.
+
+ @retval TRUE This is an Expression OpCode.
+ @retval FALSE Not an Expression OpCode.
+
+**/
+BOOLEAN
+IsExpressionOpCode (
+ IN UINT8 Operand
+ )
+{
+ if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) ||
+ ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SET_OP)) ||
+ ((Operand >= EFI_IFR_EQUAL_OP) && (Operand <= EFI_IFR_SPAN_OP)) ||
+ (Operand == EFI_IFR_CATENATE_OP) ||
+ (Operand == EFI_IFR_TO_LOWER_OP) ||
+ (Operand == EFI_IFR_TO_UPPER_OP) ||
+ (Operand == EFI_IFR_MAP_OP) ||
+ (Operand == EFI_IFR_VERSION_OP) ||
+ (Operand == EFI_IFR_SECURITY_OP)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/**
+ Calculate number of Statemens(Questions) and Expression OpCodes.
+
+ @param FormSet The FormSet to be counted.
+ @param NumberOfStatement Number of Statemens(Questions)
+ @param NumberOfExpression Number of Expression OpCodes
+
+**/
+VOID
+CountOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN OUT UINT16 *NumberOfStatement,
+ IN OUT UINT16 *NumberOfExpression
+ )
+{
+ UINT16 StatementCount;
+ UINT16 ExpressionCount;
+ UINT8 *OpCodeData;
+ UINTN Offset;
+ UINTN OpCodeLen;
+
+ Offset = 0;
+ StatementCount = 0;
+ ExpressionCount = 0;
+
+ while (Offset < FormSet->IfrBinaryLength) {
+ OpCodeData = FormSet->IfrBinaryData + Offset;
+ OpCodeLen = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ Offset += OpCodeLen;
+
+ if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode)) {
+ ExpressionCount++;
+ } else {
+ StatementCount++;
+ }
+ }
+
+ *NumberOfStatement = StatementCount;
+ *NumberOfExpression = ExpressionCount;
+}
+
+
+
+/**
+ Parse opcodes in the formset IFR binary.
+
+ @param FormSet Pointer of the FormSet data structure.
+
+ @retval EFI_SUCCESS Opcode parse success.
+ @retval Other Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Index;
+ FORM_BROWSER_FORM *CurrentForm;
+ FORM_BROWSER_STATEMENT *CurrentStatement;
+ EXPRESSION_OPCODE *ExpressionOpCode;
+ FORM_EXPRESSION *CurrentExpression;
+ UINT8 Operand;
+ UINT8 Scope;
+ UINTN OpCodeOffset;
+ UINTN OpCodeLength;
+ UINT8 *OpCodeData;
+ UINT8 ScopeOpCode;
+ FORMSET_STORAGE *Storage;
+ FORMSET_STORAGE *TempStorage;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ QUESTION_DEFAULT *CurrentDefault;
+ QUESTION_OPTION *CurrentOption;
+ UINT8 Width;
+ CHAR8 *AsciiString;
+ UINT16 NumberOfStatement;
+ UINT16 NumberOfExpression;
+ BOOLEAN SuppressForQuestion;
+ BOOLEAN SuppressForOption;
+ BOOLEAN InScopeOptionSuppress;
+ FORM_EXPRESSION *OptionSuppressExpression;
+ BOOLEAN InScopeFormSuppress;
+ FORM_EXPRESSION *FormSuppressExpression;
+ UINT16 DepthOfDisable;
+ BOOLEAN OpCodeDisabled;
+ BOOLEAN SingleOpCodeExpression;
+ BOOLEAN InScopeDefault;
+ EFI_HII_VALUE *Value;
+ UINT8 MapScopeDepth;
+ LIST_ENTRY *Link;
+ FORMSET_STORAGE *VarStorage;
+ LIST_ENTRY *MapExpressionList;
+ EFI_VARSTORE_ID TempVarstoreId;
+ BOOLEAN ConstantFlag;
+ FORMSET_DEFAULTSTORE *PreDefaultStore;
+ LIST_ENTRY *DefaultLink;
+ BOOLEAN HaveInserted;
+ BOOLEAN BitFieldStorage;
+ UINT16 TotalBits;
+
+ mInScopeSubtitle = FALSE;
+ SuppressForQuestion = FALSE;
+ SuppressForOption = FALSE;
+ InScopeFormSuppress = FALSE;
+ mInScopeSuppress = FALSE;
+ InScopeOptionSuppress = FALSE;
+ mInScopeGrayOut = FALSE;
+ mInScopeDisable = FALSE;
+ DepthOfDisable = 0;
+ OpCodeDisabled = FALSE;
+ SingleOpCodeExpression = FALSE;
+ InScopeDefault = FALSE;
+ CurrentExpression = NULL;
+ CurrentDefault = NULL;
+ CurrentOption = NULL;
+ OptionSuppressExpression = NULL;
+ FormSuppressExpression = NULL;
+ MapScopeDepth = 0;
+ Link = NULL;
+ VarStorage = NULL;
+ MapExpressionList = NULL;
+ TempVarstoreId = 0;
+ ConstantFlag = TRUE;
+ BitFieldStorage = FALSE;
+
+ //
+ // Get the number of Statements and Expressions
+ //
+ CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);
+
+ mStatementIndex = 0;
+ FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));
+ if (FormSet->StatementBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mExpressionOpCodeIndex = 0;
+ FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE));
+ if (FormSet->ExpressionBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FormSet->StorageListHead = &mVarListEntry;
+ InitializeListHead (&FormSet->DefaultStoreListHead);
+ InitializeListHead (&FormSet->FormListHead);
+ InitializeListHead (&FormSet->ExpressionListHead);
+ ResetCurrentExpressionStack ();
+ ResetMapExpressionListStack ();
+
+ CurrentForm = NULL;
+ CurrentStatement = NULL;
+
+ ResetScopeStack ();
+
+ OpCodeOffset = 0;
+ while (OpCodeOffset < FormSet->IfrBinaryLength) {
+ OpCodeData = FormSet->IfrBinaryData + OpCodeOffset;
+
+ OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+ OpCodeOffset += OpCodeLength;
+ Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+ Scope = ((EFI_IFR_OP_HEADER *) OpCodeData)->Scope;
+
+ //
+ // If scope bit set, push onto scope stack
+ //
+ if (Scope != 0) {
+ PushScope (Operand);
+ }
+
+ if (OpCodeDisabled) {
+ //
+ // DisableIf Expression is evaluated to be TRUE, try to find its end.
+ // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END
+ //
+ if (Operand == EFI_IFR_DISABLE_IF_OP) {
+ DepthOfDisable++;
+ } else if (Operand == EFI_IFR_END_OP) {
+ Status = PopScope (&ScopeOpCode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) {
+ if (DepthOfDisable == 0) {
+ mInScopeDisable = FALSE;
+ OpCodeDisabled = FALSE;
+ } else {
+ DepthOfDisable--;
+ }
+ }
+ }
+ continue;
+ }
+
+ if (IsExpressionOpCode (Operand)) {
+ ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex];
+ mExpressionOpCodeIndex++;
+
+ ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE;
+ ExpressionOpCode->Operand = Operand;
+ Value = &ExpressionOpCode->Value;
+
+ switch (Operand) {
+ case EFI_IFR_EQ_ID_VAL_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->Value, sizeof (UINT16));
+ break;
+
+ case EFI_IFR_EQ_ID_ID_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID));
+ CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID));
+ break;
+
+ case EFI_IFR_EQ_ID_VAL_LIST_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+ CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ListLength, sizeof (UINT16));
+ ExpressionOpCode->ValueList = FceAllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ValueList);
+ break;
+
+ case EFI_IFR_TO_STRING_OP:
+ case EFI_IFR_FIND_OP:
+ ExpressionOpCode->Format = (( EFI_IFR_TO_STRING *) OpCodeData)->Format;
+ break;
+
+ case EFI_IFR_STRING_REF1_OP:
+ Value->Type = EFI_IFR_TYPE_STRING;
+ CopyMem (&Value->Value.string, &(( EFI_IFR_STRING_REF1 *) OpCodeData)->StringId, sizeof (EFI_STRING_ID));
+ break;
+
+ case EFI_IFR_RULE_REF_OP:
+ ExpressionOpCode->RuleId = (( EFI_IFR_RULE_REF *) OpCodeData)->RuleId;
+ break;
+
+ case EFI_IFR_SPAN_OP:
+ ExpressionOpCode->Flags = (( EFI_IFR_SPAN *) OpCodeData)->Flags;
+ break;
+
+ case EFI_IFR_THIS_OP:
+ ASSERT (CurrentStatement != NULL);
+ ExpressionOpCode->QuestionId = CurrentStatement->QuestionId;
+ break;
+
+ case EFI_IFR_SECURITY_OP:
+ CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_SECURITY *) OpCodeData)->Permissions, sizeof (EFI_GUID));
+ break;
+
+ case EFI_IFR_GET_OP:
+ case EFI_IFR_SET_OP:
+ CopyMem (&TempVarstoreId, &((EFI_IFR_GET *) OpCodeData)->VarStoreId, sizeof (TempVarstoreId));
+ if (TempVarstoreId != 0) {
+ if (FormSet->StorageListHead->ForwardLink != NULL) {
+ Link = GetFirstNode (FormSet->StorageListHead);
+ while (!IsNull (FormSet->StorageListHead, Link)) {
+ VarStorage = FORMSET_STORAGE_FROM_LINK (Link);
+ if (VarStorage->VarStoreId == ((EFI_IFR_GET *) OpCodeData)->VarStoreId) {
+ ExpressionOpCode->VarStorage = VarStorage;
+ break;
+ }
+ Link = GetNextNode (FormSet->StorageListHead, Link);
+ }
+ }
+ if (ExpressionOpCode->VarStorage == NULL) {
+ //
+ // VarStorage is not found.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ ExpressionOpCode->ValueType = ((EFI_IFR_GET *) OpCodeData)->VarStoreType;
+ switch (ExpressionOpCode->ValueType) {
+ case EFI_IFR_TYPE_BOOLEAN:
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ ExpressionOpCode->ValueWidth = 1;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ case EFI_IFR_TYPE_STRING:
+ ExpressionOpCode->ValueWidth = 2;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ ExpressionOpCode->ValueWidth = 4;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ ExpressionOpCode->ValueWidth = 8;
+ break;
+
+ case EFI_IFR_TYPE_DATE:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_DATE);
+ break;
+
+ case EFI_IFR_TYPE_TIME:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_TIME);
+ break;
+
+ case EFI_IFR_TYPE_REF:
+ ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_REF);
+ break;
+
+ case EFI_IFR_TYPE_OTHER:
+ case EFI_IFR_TYPE_UNDEFINED:
+ case EFI_IFR_TYPE_ACTION:
+ case EFI_IFR_TYPE_BUFFER:
+ default:
+ //
+ // Invalid value type for Get/Set opcode.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ CopyMem (&ExpressionOpCode->VarStoreInfo.VarName, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarName, sizeof (EFI_STRING_ID));
+ CopyMem (&ExpressionOpCode->VarStoreInfo.VarOffset, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarOffset, sizeof (UINT16));
+ if ((ExpressionOpCode->VarStorage != NULL) &&
+ ((ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_NAME_VALUE)
+ || ((ExpressionOpCode->VarStorage->Type == EFI_IFR_VARSTORE_EFI_OP) && !ExpressionOpCode->VarStorage->NewEfiVarstore))
+ ) {
+ ExpressionOpCode->ValueName = GetToken (ExpressionOpCode->VarStoreInfo.VarName, FormSet->UnicodeBinary);
+ if (ExpressionOpCode->ValueName == NULL) {
+ //
+ // String ID is invalid.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ case EFI_IFR_QUESTION_REF1_OP:
+ CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+ break;
+
+ case EFI_IFR_QUESTION_REF3_OP:
+ if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) {
+ CopyMem (&ExpressionOpCode->DevicePath, &(( EFI_IFR_QUESTION_REF3_2 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) {
+ CopyMem (&ExpressionOpCode->Guid, &(( EFI_IFR_QUESTION_REF3_3 *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ }
+ }
+ break;
+
+ //
+ // constant
+ //
+ case EFI_IFR_TRUE_OP:
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Value->Value.b = TRUE;
+ break;
+
+ case EFI_IFR_FALSE_OP:
+ Value->Type = EFI_IFR_TYPE_BOOLEAN;
+ Value->Value.b = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = 1;
+ break;
+
+ case EFI_IFR_ZERO_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = 0;
+ break;
+
+ case EFI_IFR_ONES_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ Value->Value.u64 = 0xffffffffffffffffULL;
+ break;
+
+ case EFI_IFR_UINT8_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ Value->Value.u8 = (( EFI_IFR_UINT8 *) OpCodeData)->Value;
+ break;
+
+ case EFI_IFR_UINT16_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ CopyMem (&Value->Value.u16, &(( EFI_IFR_UINT16 *) OpCodeData)->Value, sizeof (UINT16));
+ break;
+
+ case EFI_IFR_UINT32_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ CopyMem (&Value->Value.u32, &(( EFI_IFR_UINT32 *) OpCodeData)->Value, sizeof (UINT32));
+ break;
+
+ case EFI_IFR_UINT64_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ CopyMem (&Value->Value.u64, &(( EFI_IFR_UINT64 *) OpCodeData)->Value, sizeof (UINT64));
+ break;
+
+ case EFI_IFR_UNDEFINED_OP:
+ Value->Type = EFI_IFR_TYPE_UNDEFINED;
+ break;
+
+ case EFI_IFR_VERSION_OP:
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+
+ default:
+ break;
+ }
+ //
+ // Create sub expression nested in MAP opcode
+ //
+ if ((CurrentExpression == NULL) && (MapScopeDepth > 0)) {
+ CurrentExpression = CreateExpression (CurrentForm);
+ ASSERT (MapExpressionList != NULL);
+ InsertTailList (MapExpressionList, &CurrentExpression->Link);
+ if (Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ }
+ ASSERT (CurrentExpression != NULL);
+ InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link);
+ if (Operand == EFI_IFR_MAP_OP) {
+ //
+ // Store current Map Expression List.
+ //
+ if (MapExpressionList != NULL) {
+ PushMapExpressionList (MapExpressionList);
+ }
+ //
+ // Initialize new Map Expression List.
+ //
+ MapExpressionList = &ExpressionOpCode->MapExpressionList;
+ InitializeListHead (MapExpressionList);
+ //
+ // Store current expression.
+ //
+ PushCurrentExpression (CurrentExpression);
+ CurrentExpression = NULL;
+ MapScopeDepth ++;
+ } else if (SingleOpCodeExpression) {
+ //
+ // There are two cases to indicate the end of an Expression:
+ // for single OpCode expression: one Expression OpCode
+ // for expression consists of more than one OpCode: EFI_IFR_END
+ //
+ SingleOpCodeExpression = FALSE;
+
+ if (mInScopeDisable && (CurrentForm == NULL)) {
+ //
+ // This is DisableIf expression for Form, it should be a constant expression
+ //
+ ConstantFlag = TRUE;
+ Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!ConstantFlag) {
+ StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
+ }
+ OpCodeDisabled = CurrentExpression->Result.Value.b;
+ }
+
+ CurrentExpression = NULL;
+ }
+
+ continue;
+ }
+
+ //
+ // Parse the Opcode
+ //
+ switch (Operand) {
+
+ case EFI_IFR_FORM_SET_OP:
+
+ CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
+ CopyMem (&FormSet->Help, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
+ CopyMem (&FormSet->Guid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
+
+ if (OpCodeLength > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
+ //
+ // The formset OpCode contains ClassGuid
+ //
+ FormSet->NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
+ CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID));
+ }
+ FormSet->FormSetOrder = ++mFormSetOrderParse;
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // Create a new Form for this FormSet
+ //
+ CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
+ ASSERT (CurrentForm != NULL);
+ CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
+ InitializeListHead (&CurrentForm->ExpressionListHead);
+ InitializeListHead (&CurrentForm->StatementListHead);
+
+ CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
+ CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16));
+ CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));
+
+ if (InScopeFormSuppress) {
+ //
+ // Form is inside of suppressif
+ //
+ CurrentForm->SuppressExpression = FormSuppressExpression;
+ }
+
+ if (Scope != 0) {
+ //
+ // Enter scope of a Form, suppressif will be used for Question or Option
+ //
+ SuppressForQuestion = TRUE;
+ }
+
+ //
+ // Insert into Form list of this FormSet
+ //
+ InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
+ break;
+ //
+ // Storage
+ //
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // Create a buffer Storage for this FormSet
+ //
+
+ Storage = CreateStorage (FormSet);
+ Storage->Type = EFI_IFR_VARSTORE_OP;
+
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16));
+
+ Storage->Buffer = AllocateZeroPool (Storage->Size);
+
+ AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
+ Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
+ ASSERT (Storage->Name != NULL);
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ Storage->Name[Index] = (CHAR16) AsciiString[Index];
+ }
+ Storage->FormSetOrder = mFormSetOrderParse;
+
+ //
+ // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
+ // If these two variales have the same Guid name but different size, report an error.
+ //
+ if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
+ if (Storage->Size != TempStorage->Size) {
+ StringPrint ("Error. Two modules found with VarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but with different sizes %d and %d.\n",
+ Storage->Name,
+ Storage->Guid.Data1,
+ Storage->Guid.Data2,
+ Storage->Guid.Data3,
+ Storage->Guid.Data4[0],
+ Storage->Guid.Data4[1],
+ Storage->Guid.Data4[2],
+ Storage->Guid.Data4[3],
+ Storage->Guid.Data4[4],
+ Storage->Guid.Data4[5],
+ Storage->Guid.Data4[6],
+ Storage->Guid.Data4[7],
+ Storage->Size,
+ TempStorage->Size
+ );
+ return EFI_ABORTED;
+ }
+ //
+ // Update the VarStoreId for current question to get the variable guid and name information
+ //
+ TempStorage->VarStoreId = Storage->VarStoreId;
+ TempStorage->FormSetOrder = Storage->FormSetOrder;
+ RemoveEntryList (&Storage->Link);
+ DestroyStorage(Storage);
+ }
+ break;
+
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ //
+ // Create a name/value Storage for this FormSet
+ //
+ Storage = CreateStorage (FormSet);
+ Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;
+
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+
+ Storage->FormSetOrder = mFormSetOrderParse;
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // Create a EFI variable Storage for this FormSet
+ //
+ Storage = CreateStorage (FormSet);
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&Storage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32));
+ //
+ // Check whether the EfiVarStore before UEFI2.31 or not
+ //
+ Storage->Size = sizeof (EFI_IFR_VARSTORE_EFI_OLD);
+ if (((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Header.Length == sizeof (EFI_IFR_VARSTORE_EFI_OLD)) {
+ Storage->NewEfiVarstore = FALSE;
+ Storage->Size = 0;
+ Storage->Buffer = NULL;
+ Storage->Name = NULL;
+ Storage->Size = 0;
+ } else {
+ //
+ // EfiVarStore structure for UEFI2.31
+ //
+ Storage->NewEfiVarstore = TRUE;
+ CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Size, sizeof (UINT16));
+
+ Storage->Buffer = AllocateZeroPool (Storage->Size);
+ AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
+ Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
+ ASSERT (Storage->Name != NULL);
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ Storage->Name[Index] = (CHAR16) AsciiString[Index];
+ }
+ }
+ Storage->FormSetOrder = mFormSetOrderParse;
+ //
+ // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
+ // If these two variales have the same Guid name but different size, report an error.
+ //
+ if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
+ if (Storage->Size != TempStorage->Size) {
+ StringPrint ("Error. Two modules found with EfiVarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but different sizes %d and %d.\n",
+ Storage->Name,
+ Storage->Guid.Data1,
+ Storage->Guid.Data2,
+ Storage->Guid.Data3,
+ Storage->Guid.Data4[0],
+ Storage->Guid.Data4[1],
+ Storage->Guid.Data4[2],
+ Storage->Guid.Data4[3],
+ Storage->Guid.Data4[4],
+ Storage->Guid.Data4[5],
+ Storage->Guid.Data4[6],
+ Storage->Guid.Data4[7],
+ Storage->Size,
+ TempStorage->Size
+ );
+ return EFI_ABORTED;
+ }
+ //
+ // Update the VarStoreId for current question to get the variable guid and name information
+ //
+ TempStorage->VarStoreId = Storage->VarStoreId;
+ TempStorage->FormSetOrder = Storage->FormSetOrder;
+ RemoveEntryList (&Storage->Link);
+ DestroyStorage( Storage);
+ }
+ break;
+
+ //
+ // DefaultStore
+ //
+ case EFI_IFR_DEFAULTSTORE_OP:
+ HaveInserted = FALSE;
+ DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE));
+ ASSERT (DefaultStore != NULL);
+ DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE;
+
+ CopyMem (&DefaultStore->DefaultId, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultId, sizeof (UINT16));
+ CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultName, sizeof (EFI_STRING_ID));
+
+ //
+ // Insert it to the DefaultStore list of this Formset with ascending order.
+ //
+ if (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+ DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+ while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
+ PreDefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+ DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
+ if (DefaultStore->DefaultId < PreDefaultStore->DefaultId) {
+ InsertTailList (&PreDefaultStore->Link, &DefaultStore->Link);
+ HaveInserted = TRUE;
+ break;
+ }
+ }
+ }
+ if (!HaveInserted) {
+ InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link);
+ }
+ break;
+
+ //
+ // Statements
+ //
+ case EFI_IFR_SUBTITLE_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;
+
+ if (Scope != 0) {
+ mInScopeSubtitle = TRUE;
+ }
+ break;
+
+ case EFI_IFR_TEXT_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+
+ CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));
+ break;
+
+ case EFI_IFR_RESET_BUTTON_OP:
+ CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));
+ break;
+
+ //
+ // Questions
+ //
+ case EFI_IFR_ACTION_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_ACTION;
+ //
+ // No need to deal with the EFI_IFR_ACTION
+ //
+ break;
+
+ case EFI_IFR_REF_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ Value = &CurrentStatement->HiiValue;
+ Value->Type = EFI_IFR_TYPE_REF;
+ if (OpCodeLength >= sizeof (EFI_IFR_REF)) {
+ CopyMem (&Value->Value.ref.FormId, &((EFI_IFR_REF *) OpCodeData)->FormId, sizeof (EFI_FORM_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF2)) {
+ CopyMem (&Value->Value.ref.QuestionId, &((EFI_IFR_REF2 *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF3)) {
+ CopyMem (&Value->Value.ref.FormSetGuid, &((EFI_IFR_REF3 *) OpCodeData)->FormSetId, sizeof (EFI_GUID));
+
+ if (OpCodeLength >= sizeof (EFI_IFR_REF4)) {
+ CopyMem (&Value->Value.ref.DevicePath, &((EFI_IFR_REF4 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+ }
+ }
+ }
+ }
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_REF);
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_ONE_OF *) OpCodeData)->Flags;
+ Value = &CurrentStatement->HiiValue;
+
+ if (BitFieldStorage) {
+ //
+ // Get the bit var store info (bit/byte offset, bit/byte offset)
+ //
+ CurrentStatement->QuestionReferToBitField = TRUE;
+ CurrentStatement->BitStorageWidth = CurrentStatement->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+ CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+ CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+ TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+ CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+ //
+ // Get the Minimum/Maximum/Step value(Note: bit field type has been stored as UINT32 type)
+ //
+ CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue;
+ CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue;
+ CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step;
+ } else {
+ switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue;
+ CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue;
+ CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step;
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT8);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step, sizeof (UINT16));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT16);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue, sizeof (UINT32));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue, sizeof (UINT32));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step, sizeof (UINT32));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT32);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MinValue, sizeof (UINT64));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MaxValue, sizeof (UINT64));
+ CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.Step, sizeof (UINT64));
+ CurrentStatement->StorageWidth = (UINT16) sizeof (UINT64);
+ Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if ((Operand == EFI_IFR_ONE_OF_OP) && (Scope != 0)) {
+ SuppressForOption = TRUE;
+ }
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Flags;
+ CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BUFFER;
+ CurrentStatement->BufferValue = NULL;
+ if (Scope != 0) {
+ SuppressForOption = TRUE;
+ }
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *) OpCodeData)->Flags;
+ CurrentStatement->StorageWidth = (UINT16) sizeof (BOOLEAN);
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN;
+
+ if (BitFieldStorage) {
+ //
+ // Get the bit var store info (bit/byte offset, bit/byte width)
+ //
+ CurrentStatement->QuestionReferToBitField = TRUE;
+ CurrentStatement->BitStorageWidth = 1;
+ CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+ CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+ TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+ CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+ }
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+
+ break;
+
+ case EFI_IFR_STRING_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ //
+ // MinSize is the minimum number of characters that can be accepted for this opcode,
+ // MaxSize is the maximum number of characters that can be accepted for this opcode.
+ // The characters are stored as Unicode, so the storage width should multiply 2.
+ //
+ CurrentStatement->Minimum = ((EFI_IFR_STRING *) OpCodeData)->MinSize;
+ CurrentStatement->Maximum = ((EFI_IFR_STRING *) OpCodeData)->MaxSize;
+ CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+ CurrentStatement->Flags = ((EFI_IFR_STRING *) OpCodeData)->Flags;
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+ CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth + sizeof (CHAR16));
+ //
+ // Get the UQI information
+ //
+ PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+ //
+ // Exchange the Guid and name information between VarList and Question List
+ //
+ Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+ //
+ // Remove the question which isn't stored by EfiVarStore or VarStore
+ //
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&CurrentStatement->Link);
+ DestroyStatement (FormSet, CurrentStatement);
+ }
+
+ break;
+
+ case EFI_IFR_PASSWORD_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT (CurrentStatement != NULL);
+ //
+ // MinSize is the minimum number of characters that can be accepted for this opcode,
+ // MaxSize is the maximum number of characters that can be accepted for this opcode.
+ // The characters are stored as Unicode, so the storage width should multiply 2.
+ //
+ CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *) OpCodeData)->MinSize, sizeof (UINT16));
+ CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize, sizeof (UINT16));
+ CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+ CurrentStatement->BufferValue = AllocateZeroPool ((CurrentStatement->StorageWidth + sizeof (CHAR16)));
+ break;
+
+ case EFI_IFR_DATE_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_DATE *) OpCodeData)->Flags;
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE;
+
+ if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) {
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_DATE);
+ } else {
+ //
+ // Don't assign storage for RTC type of date/time
+ //
+ CurrentStatement->Storage = NULL;
+ CurrentStatement->StorageWidth = 0;
+ }
+ break;
+
+ case EFI_IFR_TIME_OP:
+ CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+ ASSERT(CurrentStatement != NULL);
+
+ CurrentStatement->Flags = ((EFI_IFR_TIME *) OpCodeData)->Flags;
+ CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME;
+
+ if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) {
+ CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_TIME);
+ } else {
+ //
+ // Don't assign storage for RTC type of date/time
+ //
+ CurrentStatement->Storage = NULL;
+ CurrentStatement->StorageWidth = 0;
+ }
+ break;
+
+ //
+ // Default
+ //
+ case EFI_IFR_DEFAULT_OP:
+ //
+ // EFI_IFR_DEFAULT appear in scope of a Question,
+ // It creates a default value for the current question.
+ // A Question may have more than one Default value which have different default types.
+ //
+ CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
+ ASSERT (CurrentDefault != NULL);
+ CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+ CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *) OpCodeData)->Type;
+ CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *) OpCodeData)->DefaultId, sizeof (UINT16));
+ if (CurrentDefault->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
+ CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_DEFAULT *)OpCodeData)->Value);
+ ASSERT(CurrentDefault->Value.Buffer != NULL);
+ } else {
+ CopyMem(&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *)OpCodeData)->Value, OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
+ ExtendValueToU64(&CurrentDefault->Value);
+ }
+
+ //
+ // Insert to Default Value list of current Question
+ //
+ InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link);
+
+ if (Scope != 0) {
+ InScopeDefault = TRUE;
+ }
+ break;
+
+ //
+ // Option
+ //
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ ASSERT (CurrentStatement != NULL);
+ if (CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP &&
+ ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)) != 0)) {
+ //
+ // It's keep the default value for ordered list opcode.
+ //
+ CurrentDefault = AllocateZeroPool(sizeof (QUESTION_DEFAULT));
+ ASSERT(CurrentDefault != NULL);
+ CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+ CurrentDefault->Value.Type = EFI_IFR_TYPE_BUFFER;
+ if ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & EFI_IFR_OPTION_DEFAULT) != 0) {
+ CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ } else {
+ CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ }
+
+ CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value));
+ CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value);
+ ASSERT(CurrentDefault->Value.Buffer != NULL);
+
+ //
+ // Insert to Default Value list of current Question
+ //
+ InsertTailList(&CurrentStatement->DefaultListHead, &CurrentDefault->Link);
+ break;
+ }
+ //
+ // EFI_IFR_ONE_OF_OPTION appear in scope of a Question.
+ // It create a selection for use in current Question.
+ //
+ CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));
+ ASSERT (CurrentOption != NULL);
+ CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;
+
+ CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags;
+ CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type;
+ CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Option, sizeof (EFI_STRING_ID));
+ CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ ExtendValueToU64 (&CurrentOption->Value);
+
+ if (InScopeOptionSuppress) {
+ CurrentOption->SuppressExpression = OptionSuppressExpression;
+ }
+
+ //
+ // Insert to Option list of current Question
+ //
+ InsertTailList (&CurrentStatement->OptionListHead, &CurrentOption->Link);
+
+ //
+ // Now we know the Storage width of nested Ordered List
+ //
+ if ((CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (CurrentStatement->BufferValue == NULL)) {
+ Width = 1;
+ switch (CurrentOption->Value.Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ Width = 1;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ Width = 2;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ Width = 4;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ Width = 8;
+ break;
+
+ default:
+ //
+ // Invalid type for Ordered List
+ //
+ break;
+ }
+
+ CurrentStatement->StorageWidth = (UINT16) (CurrentStatement->MaxContainers * Width);
+ CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth);
+ CurrentStatement->ValueType = CurrentOption->Value.Type;
+ if (CurrentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
+ CurrentStatement->HiiValue.Buffer = CurrentStatement->BufferValue;
+ CurrentStatement->HiiValue.BufferLen = CurrentStatement->StorageWidth;
+ }
+ }
+ break;
+
+ //
+ // Conditional
+ //
+ case EFI_IFR_NO_SUBMIT_IF_OP:
+ case EFI_IFR_INCONSISTENT_IF_OP:
+ //
+ // Create an Expression node
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID));
+
+ if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) {
+ CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF;
+ InsertTailList (&CurrentStatement->NoSubmitListHead, &CurrentExpression->Link);
+ } else {
+ CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF;
+ InsertTailList (&CurrentStatement->InconsistentListHead, &CurrentExpression->Link);
+ }
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_WARNING_IF_OP:
+ //
+ // Create an Expression node
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *) OpCodeData)->Warning, sizeof (EFI_STRING_ID));
+ CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeData)->TimeOut;
+ CurrentExpression->Type = EFI_HII_EXPRESSION_WARNING_IF;
+ InsertTailList (&CurrentStatement->WarningListHead, &CurrentExpression->Link);
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_SUPPRESS_IF_OP:
+ //
+ // Question and Option will appear in scope of this OpCode
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF;
+
+ if (CurrentForm == NULL) {
+ InsertTailList (&FormSet->ExpressionListHead, &CurrentExpression->Link);
+ } else {
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+ }
+
+ if (SuppressForOption) {
+ InScopeOptionSuppress = TRUE;
+ OptionSuppressExpression = CurrentExpression;
+ } else if (SuppressForQuestion) {
+ mInScopeSuppress = TRUE;
+ mSuppressExpression = CurrentExpression;
+ } else {
+ InScopeFormSuppress = TRUE;
+ FormSuppressExpression = CurrentExpression;
+ }
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_GRAY_OUT_IF_OP:
+ //
+ // Questions will appear in scope of this OpCode
+ //
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ mInScopeGrayOut = TRUE;
+ mGrayOutExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_DISABLE_IF_OP:
+ //
+ // The DisableIf expression should only rely on constant, so it could be
+ // evaluated at initialization and it will not be queued
+ //
+ CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+ ASSERT (CurrentExpression != NULL);
+ CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE;
+ CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF;
+ InitializeListHead (&CurrentExpression->OpCodeListHead);
+
+ if (CurrentForm != NULL) {
+ //
+ // This is DisableIf for Question, enqueue it to Form expression list
+ //
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+ }
+
+ mDisableExpression = CurrentExpression;
+ mInScopeDisable = TRUE;
+ OpCodeDisabled = FALSE;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ //
+ // Expression
+ //
+ case EFI_IFR_VALUE_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ if (InScopeDefault) {
+ //
+ // Used for default (EFI_IFR_DEFAULT)
+ //
+ CurrentDefault->ValueExpression = CurrentExpression;
+ } else {
+ //
+ // If used for a question, then the question will be read-only
+ //
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->ValueExpression = CurrentExpression;
+ }
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_RULE_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_RULE;
+
+ CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_READ_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_READ;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->ReadExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ case EFI_IFR_WRITE_OP:
+ CurrentExpression = CreateExpression (CurrentForm);
+ CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE;
+ InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ CurrentStatement->WriteExpression = CurrentExpression;
+
+ //
+ // Take a look at next OpCode to see whether current expression consists
+ // of single OpCode
+ //
+ if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+ SingleOpCodeExpression = TRUE;
+ }
+ break;
+
+ //
+ // Image
+ //
+ case EFI_IFR_IMAGE_OP:
+ //
+ // Get ScopeOpcode from top of stack
+ //
+ PopScope (&ScopeOpCode);
+ PushScope (ScopeOpCode);
+
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ ASSERT (CurrentForm != NULL);
+ break;
+
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ break;
+
+ default:
+ //
+ // Make sure CurrentStatement is not NULL.
+ // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+ // file is wrongly generated by tools such as VFR Compiler.
+ //
+ ASSERT (CurrentStatement != NULL);
+ break;
+ }
+ break;
+
+ //
+ // Refresh
+ //
+ case EFI_IFR_REFRESH_OP:
+ break;
+
+ //
+ // Refresh guid.
+ //
+ case EFI_IFR_REFRESH_ID_OP:
+ break;
+
+ //
+ // Modal tag
+ //
+ case EFI_IFR_MODAL_TAG_OP:
+ break;
+
+ //
+ // Vendor specific
+ //
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid ((EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarGuid)==0) {
+ Scope = 0;
+ BitFieldStorage = TRUE;
+ }
+ break;
+
+ //
+ // Scope End
+ //
+ case EFI_IFR_END_OP:
+ BitFieldStorage = FALSE;
+ Status = PopScope (&ScopeOpCode);
+ if (EFI_ERROR (Status)) {
+ ResetScopeStack ();
+ return Status;
+ }
+
+ switch (ScopeOpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ //
+ // End of FormSet, update FormSet IFR binary length
+ // to stop parsing substantial OpCodes
+ //
+ FormSet->IfrBinaryLength = OpCodeOffset;
+ break;
+
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // End of Form
+ //
+ CurrentForm = NULL;
+ SuppressForQuestion = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ //
+ // End of Option
+ //
+ CurrentOption = NULL;
+ break;
+
+ case EFI_IFR_SUBTITLE_OP:
+ mInScopeSubtitle = FALSE;
+ break;
+
+ case EFI_IFR_NO_SUBMIT_IF_OP:
+ case EFI_IFR_INCONSISTENT_IF_OP:
+ case EFI_IFR_WARNING_IF_OP:
+ //
+ // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF
+ //
+ break;
+
+ case EFI_IFR_SUPPRESS_IF_OP:
+ if (SuppressForOption) {
+ InScopeOptionSuppress = FALSE;
+ } else if (SuppressForQuestion) {
+ mInScopeSuppress = FALSE;
+ } else {
+ InScopeFormSuppress = FALSE;
+ }
+ break;
+
+ case EFI_IFR_GRAY_OUT_IF_OP:
+ mInScopeGrayOut = FALSE;
+ break;
+
+ case EFI_IFR_DISABLE_IF_OP:
+ mInScopeDisable = FALSE;
+ OpCodeDisabled = FALSE;
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_ORDERED_LIST_OP:
+ SuppressForOption = FALSE;
+ break;
+
+ case EFI_IFR_DEFAULT_OP:
+ InScopeDefault = FALSE;
+ break;
+
+ case EFI_IFR_MAP_OP:
+ //
+ // Get current Map Expression List.
+ //
+ Status = PopMapExpressionList ((VOID **) &MapExpressionList);
+ if (Status == EFI_ACCESS_DENIED) {
+ MapExpressionList = NULL;
+ }
+ //
+ // Get current expression.
+ //
+ Status = PopCurrentExpression ((VOID **) &CurrentExpression);
+ ASSERT (!EFI_ERROR (Status));
+ ASSERT (MapScopeDepth > 0);
+ MapScopeDepth --;
+ break;
+
+ default:
+ if (IsExpressionOpCode (ScopeOpCode)) {
+ if (mInScopeDisable && (CurrentForm == NULL)) {
+ //
+ // This is DisableIf expression for Form, it should be a constant expression
+ //
+ ASSERT (CurrentExpression != NULL);
+ ConstantFlag = TRUE;
+ Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!ConstantFlag) {
+ StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
+ }
+ OpCodeDisabled = CurrentExpression->Result.Value.b;
+ //
+ // DisableIf Expression is only used once and not queued, free it
+ //
+ DestroyExpression (CurrentExpression);
+ }
+
+ //
+ // End of current Expression
+ //
+ CurrentExpression = NULL;
+ }
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search an Option of a Question by its value.
+
+ @param Question The Question
+ @param OptionValue Value for Option to be searched.
+
+ @retval Pointer Pointer to the found Option.
+ @retval NULL Option not found.
+
+**/
+QUESTION_OPTION *
+ValueToOption (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN EFI_HII_VALUE *OptionValue
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ if (CompareHiiValue (&Option->Value, OptionValue, FormSet) == 0) {
+ return Option;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ Set value of a data element in an Array by its Index.
+
+ @param Array The data array.
+ @param Type Type of the data in this array.
+ @param Index Zero based index for data in this array.
+ @param Value The value to be set.
+
+**/
+VOID
+SetArrayData (
+ IN VOID *Array,
+ IN UINT8 Type,
+ IN UINTN Index,
+ IN UINT64 Value
+ )
+{
+
+ ASSERT (Array != NULL);
+
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ *(((UINT8 *) Array) + Index) = (UINT8) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ *(((UINT16 *) Array) + Index) = (UINT16) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ *(((UINT32 *) Array) + Index) = (UINT32) Value;
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ *(((UINT64 *) Array) + Index) = (UINT64) Value;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Reset Question of five kinds to its default value.
+
+ @param FormSet The form set.
+ @param Form The form.
+ @param Question The question.
+ @param DefaultId The default Id.
+ @param DefaultId The platform Id.
+
+ @retval EFI_SUCCESS Question is reset to default value.
+
+**/
+EFI_STATUS
+GetQuestionDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ QUESTION_DEFAULT *Default;
+ QUESTION_OPTION *Option;
+ EFI_HII_VALUE *HiiValue;
+ UINT8 Index;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+ BOOLEAN ConstantFlag;
+ UINT16 OriginalDefaultId;
+ FORMSET_DEFAULTSTORE *DefaultStore;
+ LIST_ENTRY *DefaultLink;
+ CHAR16 *VarDefaultName;
+
+ VarDefaultName = NULL;
+ Status = EFI_SUCCESS;
+ ConstantFlag = TRUE;
+ OriginalDefaultId = DefaultId;
+ DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+ //
+ // Statement don't have storage, skip them
+ //
+ if (Question->QuestionId == 0) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Return if no any kinds of
+ //
+ if ((Question->Operand != EFI_IFR_CHECKBOX_OP)
+ && (Question->Operand != EFI_IFR_ONE_OF_OP)
+ && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
+ && (Question->Operand != EFI_IFR_NUMERIC_OP)
+ && (Question->Operand != EFI_IFR_STRING_OP)
+ ) {
+ return EFI_ABORTED;
+ }
+ //
+ // Search the variable for this question (Compatible with the old EfiVarStore before UEFI2.31)
+ //
+
+ //
+ //VarStoreInfoDepending on the type of variable store selected,
+ //this contains either a 16-bit Buffer Storage offset (VarOffset)
+ //or a Name/Value or EFI Variable name (VarName).
+ //
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ FormSet->StorageListHead,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ //
+ // There are three ways to specify default value for a Question:
+ // 1, use nested EFI_IFR_DEFAULT
+ // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
+ // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
+ //
+ReGetDefault:
+ HiiValue = &Question->HiiValue;
+ //
+ // EFI_IFR_DEFAULT has highest priority
+ //
+ if (!IsListEmpty (&Question->DefaultListHead)) {
+ Link = GetFirstNode (&Question->DefaultListHead);
+ while (!IsNull (&Question->DefaultListHead, Link)) {
+ Default = QUESTION_DEFAULT_FROM_LINK (Link);
+
+ if (Default->DefaultId == DefaultId) {
+ if (Default->ValueExpression != NULL) {
+ //
+ // Default is provided by an Expression, evaluate it
+ //
+ Status = EvaluateExpression (FormSet, Form, Default->ValueExpression, &ConstantFlag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
+ if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
+ CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
+ Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
+ } else {
+ CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
+ Question->HiiValue.BufferLen = Question->StorageWidth;
+ }
+ FreePool(Default->ValueExpression->Result.Buffer);
+ }
+ HiiValue->Type = Default->ValueExpression->Result.Type;
+ CopyMem(&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
+ } else {
+ //
+ // Default value is embedded in EFI_IFR_DEFAULT
+ //
+ if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ CopyMem(HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
+ } else {
+ CopyMem(HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
+ }
+ }
+ if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+ CopyMem(VarBuffer, HiiValue->Buffer, HiiValue->BufferLen);
+ } else if (HiiValue->Type == EFI_IFR_TYPE_STRING){
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ HiiValue->Value.string,
+ EN_US,
+ &VarDefaultName
+ );
+ if (VarDefaultName == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ if (Question->StorageWidth > FceStrSize(VarDefaultName)) {
+ ZeroMem (VarBuffer, Question->StorageWidth);
+ CopyMem (VarBuffer, VarDefaultName, FceStrSize(VarDefaultName));
+ } else {
+ CopyMem (VarBuffer, VarDefaultName, Question->StorageWidth);
+ }
+ } else {
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem(VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ }
+ return EFI_SUCCESS;
+ }
+ if (Default->DefaultId == DefaultId) {
+ return EFI_SUCCESS;
+ }
+ Link = GetNextNode (&Question->DefaultListHead, Link);
+ }
+ }
+
+ if (HiiValue->Buffer == NULL) {
+ ZeroMem (HiiValue, sizeof (EFI_HII_VALUE));
+ }
+
+ //
+ // EFI_ONE_OF_OPTION
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // OneOfOption could only provide Standard and Manufacturing default
+ //
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
+ ) {
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+ }
+ }
+
+ //
+ // EFI_IFR_CHECKBOX - lowest priority
+ //
+ if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
+ if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+ //
+ // Checkbox could only provide Standard and Manufacturing default
+ //
+ if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
+ ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
+ ) {
+ HiiValue->Value.b = TRUE;
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
+ // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
+ // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
+ //
+ while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) {
+ DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+ DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink);
+ DefaultId = DefaultStore->DefaultId;
+ if (DefaultId == OriginalDefaultId) {
+ continue;
+ }
+ goto ReGetDefault;
+ }
+
+ //
+ // For Questions without default
+ //
+ Status = EFI_NOT_FOUND;
+ switch (Question->Operand) {
+ case EFI_IFR_CHECKBOX_OP:
+ HiiValue->Value.b = FALSE;
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ //
+ // Take minimum value as numeric default value
+ //
+ if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
+ HiiValue->Value.u64 = Question->Minimum;
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ //
+ // Take first oneof option as oneof's default value
+ //
+ if (ValueToOption (FormSet, Question, HiiValue) == NULL) {
+ Link = GetFirstNode (&Question->OptionListHead);
+ if (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+ if (Question->QuestionReferToBitField) {
+ SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+ } else {
+ CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ //
+ // Take option sequence in IFR as ordered list's default value
+ //
+ Index = 0;
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+
+ SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
+ SetArrayData (VarBuffer, Question->ValueType, Index, Option->Value.Value.u64);
+
+ Index++;
+ if (Index >= Question->MaxContainers) {
+ break;
+ }
+
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the value to the variable of platformId question.
+
+ @param PlatformId The form set.
+
+ @retval EFI_SUCCESS Set successfully.
+
+**/
+EFI_STATUS
+AssignThePlatformId (
+ IN UINT64 PlatformId
+ )
+{
+ EFI_STATUS Status;
+ FORMSET_STORAGE *VarList;
+ UINT8 *VarBuffer;
+
+ Status = EFI_SUCCESS;
+ VarBuffer = NULL;
+ //
+ // Set the Storage
+ //
+ Status = SearchVarStorage (
+ &mMultiPlatformParam.PlatformIdQuestion,
+ NULL,
+ mMultiPlatformParam.PlatformIdQuestion.VarStoreInfo.VarOffset,
+ &mVarListEntry,
+ (CHAR8 **)&VarBuffer,
+ &VarList
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ CopyMem (VarBuffer, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
+ //
+ // Set the HIIvalue of this questions
+ //
+ CopyMem (&mMultiPlatformParam.Question->HiiValue.Value.u64, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
+
+ switch (mMultiPlatformParam.PlatformIdWidth) {
+ case sizeof (UINT8):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
+ break;
+
+ case sizeof (UINT16):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_16;
+ break;
+
+ case sizeof (UINT32):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_32;
+ break;
+
+ case sizeof (UINT64):
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ break;
+
+ default:
+ mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Reset Questions to their default value in a Form, Formset or System.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param DefaultId The default Id
+ @param PlatformId The platform Id
+ @param SettingScope Setting Scope for Default action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *FormLink;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *FormSetEntryListHead;
+ FORM_BROWSER_STATEMENT *Question;
+ //
+ // Check the supported setting level.
+ //
+ if (SettingScope >= MaxLevel) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (SettingScope == FormLevel) {
+ //
+ // Extract Form default
+ //
+ Link = GetFirstNode (&Form->StatementListHead);
+ while (!IsNull (&Form->StatementListHead, Link)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&Form->StatementListHead, Link);
+ //
+ // Re-set the platformId before calcuate the platformId of every question to avoid over-written.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ Status = AssignThePlatformId (PlatformId);
+ if (EFI_ERROR (Status)) {
+ StringPrint ("Error. Failed to assign the platformId.\n");
+ return Status;
+ }
+ }
+ //
+ // Reset Question to its default value, and store the default to variable
+ //
+ Status = GetQuestionDefault (FormSet, Form, Question, DefaultId, PlatformId);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ }
+ } else if (SettingScope == FormSetLevel) {
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ ExtractDefault (FormSet, Form, DefaultId, PlatformId, FormLevel);
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ } else if (SettingScope == SystemLevel) {
+ //
+ // Parse Fromset one by one
+ //
+ FormSetEntryListHead = &mFormSetListEntry;
+
+ FormLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
+ ExtractDefault (FormSet, NULL, DefaultId, PlatformId, FormSetLevel);
+ FormLink = GetNextNode (FormSetEntryListHead, FormLink);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether existed the UQI in Current Unicode String.
+
+ @param UniPackge A pointer to a Null-terminated Unicode string Array.
+
+ @return TRUE If find the uqi, return TRUE
+ @return FALSE Otherwise, return FALSE
+
+**/
+static
+BOOLEAN
+IsUqiOrNot (
+ IN UINT8 *UniPackge
+ )
+{
+ CHAR8 *UniBin;
+ UINTN UniLength;
+ UINTN Index;
+ BOOLEAN FindIt;
+
+ UniBin = (CHAR8 *) UniPackge + 4;
+ Index = 4;
+ FindIt = FALSE;
+ UniLength = *(UINT32 *) UniPackge;
+
+ if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+ //
+ // Search the uqi language
+ //
+ while ((Index < UniLength) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS){
+ if (!strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi")) {
+ FindIt = TRUE;
+ break;
+ }
+ Index = Index + ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+ }
+ }
+ return FindIt;
+}
+
+ /**
+ Returns Length of UQI string (in CHAR16) (not including null termination).
+
+ @param UniPackge A pointer to a UQI string.
+
+ @return Number Length of UQIL string (in words) or 0
+
+**/
+static
+UINT16
+GetUqiNum (
+ IN CHAR16 *UniString
+ )
+{
+ UINT16 Number;
+
+ if (UniString == NULL) {
+ return 0;
+ }
+ for (Number = 0; UniString[Number] != 0; Number++) {
+ ;
+ }
+ return Number;
+}
+
+/**
+ Print the formset title information.
+
+ @param FormSet The pointer to the formset.
+
+ @return NULL.
+
+**/
+static
+VOID
+StringPrintormSetTitle (
+ IN FORM_BROWSER_FORMSET *FormSet
+ )
+{
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ VarDefaultName = NULL;
+
+ StringPrint("\n\n// Form Set: ");
+
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ FormSet->FormSetTitle,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+
+ StringPrint("\n// %s",FORM_SET_GUID_PREFIX);
+ StringPrint(
+ EFI_GUID_FORMAT,
+ FormSet->Guid.Data1, FormSet->Guid.Data2,
+ FormSet->Guid.Data3, FormSet->Guid.Data4[0],
+ FormSet->Guid.Data4[1],FormSet->Guid.Data4[2],
+ FormSet->Guid.Data4[3],FormSet->Guid.Data4[4],
+ FormSet->Guid.Data4[5],FormSet->Guid.Data4[6],
+ FormSet->Guid.Data4[7]);
+ StringPrint("\n");
+
+ if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && FormSet->FormSetTitle != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+}
+
+/**
+ Print the formset title information.
+
+ @param FormSet The pointer to the formset.
+ @param Question The pointer to the question of ONE_OF.
+
+ @return NULL.
+
+**/
+static
+EFI_STATUS
+PrintOneOfOptions (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_STATEMENT *Question
+ )
+{
+ LIST_ENTRY *Link;
+ QUESTION_OPTION *Option;
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ VarDefaultName = NULL;
+
+ if ((Question->Operand != EFI_IFR_ONE_OF_OP)
+ && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
+ ) {
+ return EFI_ABORTED;
+ }
+
+ Link = GetFirstNode (&Question->OptionListHead);
+ while (!IsNull (&Question->OptionListHead, Link)) {
+ Option = QUESTION_OPTION_FROM_LINK (Link);
+ if (Question->QuestionReferToBitField) {
+ StringPrint("// %08X = ", Option->Value.Value.u32);
+ } else {
+ switch(Option->Value.Type) {
+
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ StringPrint("// %02X = ", Option->Value.Value.u8);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ StringPrint("// %04X = ", Option->Value.Value.u16);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ StringPrint("// %08X = ", Option->Value.Value.u32);
+ break;
+
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ StringPrint("// %016llX = ", Option->Value.Value.u64);
+ break;
+
+ case EFI_IFR_TYPE_BOOLEAN:
+ StringPrint("// %X = ", Option->Value.Value.b);
+ break;
+
+ case EFI_IFR_TYPE_STRING:
+ StringPrint("// %X = ", Option->Value.Value.string);
+ break;
+
+ default:
+ break;
+ }
+ }
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Option->Text,
+ EN_US,
+ &VarDefaultName
+ );
+
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Option->Text != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+ Link = GetNextNode (&Question->OptionListHead, Link);
+ }
+ return Status;
+}
+
+/**
+ Print the form title information.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+
+ @return NULL.
+
+**/
+static
+VOID
+StringPrintormTitle (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form
+ )
+{
+ CHAR16 *VarDefaultName;
+ EFI_STATUS Status;
+
+ VarDefaultName = NULL;
+
+ StringPrint("\n// Form: ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Form->FormTitle,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+
+ if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Form->FormTitle != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+
+}
+
+/**
+ Print the information of questions.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param Question The pointer to the question.
+ @param PrintOrNot Decide whether print or not.
+
+ @return NULL.
+
+**/
+static
+VOID
+PrintQuestion (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN BOOLEAN PrintOrNot
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VarDefaultName;
+ UINT16 UqiStringLength;
+ BOOLEAN HaveUQIlanguage;
+
+ Status = EFI_SUCCESS;
+ VarDefaultName = NULL;
+ UqiStringLength = 0;
+
+ HaveUQIlanguage = IsUqiOrNot (FormSet->UnicodeBinary);
+
+ switch (Question->Operand) {
+
+ case EFI_IFR_SUBTITLE_OP:
+ if (PrintOrNot) {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ if ((VarDefaultName != NULL) && (FceStrCmp (VarDefaultName, L"") != 0)) {
+ StringPrint("// Subtitle: ");
+ StringPrint("// ");
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ }
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the Question
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = ONE_OF;
+
+ if (PrintOrNot) {
+ StringPrint("ONE_OF ");
+
+ LogIfrValue (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ //
+ // Print ONE_OF_OPTION
+ //
+ PrintOneOfOptions (FormSet, Question);
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = CHECKBOX;
+ if (PrintOrNot) {
+ StringPrint("CHECKBOX ");
+ LogIfrValue (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ StringPrint("// 0 = Unchecked\n");
+ StringPrint("// 1 = Checked\n");
+ }
+ break;
+
+ case EFI_IFR_STRING_OP:
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = STRING;
+ if (PrintOrNot) {
+ StringPrint("STRING ");
+ LogIfrValueStr (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = NUMERIC;
+ if (PrintOrNot) {
+ StringPrint("NUMERIC ");
+ LogIfrValue (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+
+ if (Question->QuestionReferToBitField) {
+ StringPrint("// Minimum = %08llX \n", Question->Minimum);
+ StringPrint("// Maximum = %08llX \n", Question->Maximum);
+ StringPrint("// Step = %08llX \n", Question->Step);
+ } else {
+ switch (Question->StorageWidth) {
+
+ case sizeof (UINT8):
+ StringPrint("// Minimum = %02llX \n", Question->Minimum);
+ StringPrint("// Maximum = %02llX \n", Question->Maximum);
+ StringPrint("// Step = %02llX \n", Question->Step);
+ break;
+
+ case sizeof (UINT16):
+ StringPrint("// Minimum = %04llX \n", Question->Minimum);
+ StringPrint("// Maximum = %04llX \n", Question->Maximum);
+ StringPrint("// Step = %04llX \n", Question->Step);
+ break;
+
+ case sizeof (UINT32):
+ StringPrint("// Minimum = %08llX \n", Question->Minimum);
+ StringPrint("// Maximum = %08llX \n", Question->Maximum);
+ StringPrint("// Step = %08llX \n", Question->Step);
+ break;
+
+ case sizeof (UINT64):
+ StringPrint("// Minimum = %016llX \n", Question->Minimum);
+ StringPrint("// Maximum = %016llX \n", Question->Maximum);
+ StringPrint("// Step = %016llX \n", Question->Step);
+ break;
+
+ default:
+ StringPrint("0000 // Width > 16 is not supported -- FAILURE");
+ break;
+ }
+ }
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+
+ if( HaveUQIlanguage ) {
+ Status = FindDefaultName (
+ &(FormSet->UqiStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ UQI,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ UqiStringLength = GetUqiNum (VarDefaultName);
+
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ } else {
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+
+ assert (!EFI_ERROR (Status));
+
+ UqiStringLength = GetUqiNum (VarDefaultName);
+ if (PrintOrNot) {
+ if (UqiStringLength > 0) {
+ StringPrint("\nQ %04X ", UqiStringLength);
+ LogUqi(VarDefaultName);
+ } else {
+ StringPrint("\n// [No UQI] ");
+ }
+ }
+ }
+ //
+ //Record the UQi to the HiiObjList
+ //
+ Question->Uqi.HexNum = UqiStringLength;
+ Question->Uqi.Data = VarDefaultName;
+ Question->Uqi.Type = ORDERED_LIST;
+
+ if (PrintOrNot) {
+ StringPrint("ORDERED_LIST %04X ", Question->MaxContainers);
+
+ LogIfrValueList (
+ FormSet,
+ Question
+ );
+ StringPrint(" // ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Prompt,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ }
+ //
+ // Print ONE_OF_OPTION
+ //
+ PrintOneOfOptions (FormSet, Question);
+ break;
+
+ default:
+ break;
+ }
+
+ if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Prompt != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+
+ if (PrintOrNot && Question->Storage) {
+ StringPrint("// size = 0x%x", Question->StorageWidth);
+ StringPrint("\n// offset = 0x%x", Question->VarStoreInfo.VarOffset);
+ StringPrint("\n// name = ");
+ LogUnicodeString(Question->VariableName);
+ StringPrint("\n// guid = ");
+ StringPrint(
+ EFI_GUID_FORMAT,
+ Question->Guid.Data1, Question->Guid.Data2,
+ Question->Guid.Data3, Question->Guid.Data4[0],
+ Question->Guid.Data4[1],Question->Guid.Data4[2],
+ Question->Guid.Data4[3],Question->Guid.Data4[4],
+ Question->Guid.Data4[5],Question->Guid.Data4[6],
+ Question->Guid.Data4[7]
+ );
+ StringPrint("\n// attribute = 0x%x", Question->Attributes);
+ StringPrint("\n// help = ");
+ Status = FindDefaultName (
+ &(FormSet->EnUsStringList),
+ FormSet->UnicodeBinary,
+ Question->Help,
+ EN_US,
+ &VarDefaultName
+ );
+ assert (!EFI_ERROR (Status));
+ LogUnicodeString (VarDefaultName);
+ StringPrint("\n");
+ if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Help != 0) {
+ free (VarDefaultName);
+ VarDefaultName = NULL;
+ }
+ }
+
+}
+
+/**
+ Check whether current Formset or Form is NULL. If no valid questions, return FASLE.
+
+ @param FormSet The pointer to the formset.
+ @param FormSet The pointer to the form.
+ @param IsFormSet FormSet or Form.
+
+ @retval TRUE
+ @return FALSE
+**/
+BOOLEAN
+CheckFormSetOrFormNull (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN BOOLEAN IsFormSet
+ )
+{
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+
+ FormLink = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+
+ //
+ // Parse all forms in formset
+ //
+ if (IsFormSet) {
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ if (Question->Type == EFI_IFR_VARSTORE_EFI_OP
+ && Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ }
+ //
+ //If invalid variable type, skip it.
+ //
+ if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
+ && (Question->Type != EFI_IFR_VARSTORE_OP)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ return TRUE;
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ } else {
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ //
+ // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+ //
+ if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
+ && Question->NewEfiVarstore
+ && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ }
+ //
+ //If invalid variable type, skip it.
+ //
+ if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
+ && (Question->Type != EFI_IFR_VARSTORE_OP)) {
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ continue;
+ }
+ return TRUE;
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Print all ONE_OF ORDER_LIST NUMERIC STRING and CHECKBOX in all fromsets.
+
+ @param Formset The pointer to the entry of the fromset list
+ @param Formset The pointer to the entry of the storage list
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+PrintInfoInAllFormset (
+ IN LIST_ENTRY *FormSetEntryListHead,
+ IN LIST_ENTRY *StorageEntryListHead
+ )
+{
+ EFI_STATUS Status;
+ FORM_BROWSER_FORMSET *FormSet;
+ LIST_ENTRY *FormSetLink;
+ LIST_ENTRY *FormLink;
+ FORM_BROWSER_FORM *Form;
+ FORM_BROWSER_STATEMENT *Question;
+ LIST_ENTRY *QuestionLink;
+ FORMSET_STORAGE *Storage;
+ CHAR8 *VarBuffer;
+ LIST_ENTRY *TempStorageLink;
+ UINT32 Index;
+ BOOLEAN Skip;
+ BOOLEAN ConstantFlag;
+
+ Status = EFI_SUCCESS;
+ FormSet = NULL;
+ FormSetLink = NULL;
+ FormLink = NULL;
+ Form = NULL;
+ Question = NULL;
+ QuestionLink = NULL;
+ Storage = NULL;
+ VarBuffer = NULL;
+ TempStorageLink = NULL;
+ Index = 0;
+ Skip = FALSE;
+ ConstantFlag = TRUE;
+ //
+ // Print platformId, defaultId and platformIdUqi
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot) {
+ StringPrint("\n\n// FCEKEY DEFAULT_ID:");
+ TempStorageLink = GetFirstNode (StorageEntryListHead);
+ Storage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ StringPrint (" %4d", Storage->DefaultId[Index]);
+ }
+ StringPrint("\n\n//FCEKEY PLATFORM_ID:");
+ for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+ StringPrint (" %4lld", Storage->PlatformId[Index]);
+ }
+ if (mMultiPlatformParam.Uqi.Data != NULL) {
+ StringPrint("\n\n//FCEKEY PLATFORM_UQI:");
+ StringPrint(" %04X ", mMultiPlatformParam.Uqi.HexNum);
+ LogUqi(mMultiPlatformParam.Uqi.Data);
+ }
+ }
+ FormSetLink = GetFirstNode (FormSetEntryListHead);
+ while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+ //
+ //Assign the new storage list
+ //
+ FormSet->StorageListHead = StorageEntryListHead;
+
+ if (CheckFormSetOrFormNull (FormSet, NULL, TRUE)) {
+ StringPrintormSetTitle (FormSet);
+ } else {
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ continue;
+ }
+ //
+ // Parse all forms in formset
+ //
+ FormLink = GetFirstNode (&FormSet->FormListHead);
+
+ while (!IsNull (&FormSet->FormListHead, FormLink)) {
+ Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+
+ if (CheckFormSetOrFormNull (NULL, Form, FALSE)) {
+ StringPrintormTitle(FormSet,Form);
+ } else {
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ continue;
+ }
+ //
+ // Parse five kinds of Questions in Form
+ //
+ QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+ while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+ Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+ //
+ // Parse five kinds of Questions in Form
+ //
+ if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+ || (Question->Operand == EFI_IFR_NUMERIC_OP)
+ || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+ || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+ || (Question->Operand == EFI_IFR_SUBTITLE_OP)
+ || (Question->Operand == EFI_IFR_STRING_OP)
+ ) {
+ Skip = FALSE;
+
+ //
+ //Only output the questions stored by EFI_IFR_VARSTORE_EFI_OP.
+ //
+ if (mMultiPlatformParam.MultiPlatformOrNot
+ && (Question->Operand != EFI_IFR_SUBTITLE_OP)
+ ) {
+ Status = SearchVarStorage (
+ Question,
+ NULL,
+ Question->VarStoreInfo.VarOffset,
+ StorageEntryListHead,
+ (CHAR8 **)&VarBuffer,
+ &Storage
+ );
+
+ if (EFI_ERROR (Status)) {
+ Skip = TRUE;
+ }
+ }
+ //
+ // If Question is constant expression and "disabledIf True", don't output it.
+ //
+ ConstantFlag = TRUE;
+ if (!Skip && (Question->DisableExpression != NULL)) {
+ Status = EvaluateExpression (FormSet, Form, Question->DisableExpression, &ConstantFlag);
+ if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b && ConstantFlag) {
+ Skip = TRUE;
+ }
+ }
+
+ if (!Skip) {
+ PrintQuestion(FormSet, Form, Question, TRUE);
+ }
+ }
+ QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+ }
+
+ FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+ }
+ FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/Tools/FCE/IfrParse.h b/Platform/Intel/Tools/FCE/IfrParse.h
new file mode 100644
index 0000000000..29a878a191
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/IfrParse.h
@@ -0,0 +1,789 @@
+/** @file
+
+ Parser for IFR binary encoding.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IFR_PARSE_H_
+#define _IFR_PARSE_H_
+
+#include "Common.h"
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/MdeModuleHii.h>
+
+//
+// Scope for Browser action. It may be Form, FormSet or System level.
+//
+typedef enum {
+ FormLevel,
+ FormSetLevel,
+ SystemLevel,
+ MaxLevel
+} BROWSER_SETTING_SCOPE;
+
+///
+///Old EFI_IFR_VARSTORE_EFI structure to complible with UEFI 2.3
+///
+typedef struct _EFI_IFR_VARSTORE_EFI_OLD {
+ EFI_IFR_OP_HEADER Header;
+ EFI_VARSTORE_ID VarStoreId;
+ EFI_GUID Guid;
+ UINT32 Attributes;
+} EFI_IFR_VARSTORE_EFI_OLD;
+
+///
+/// The languages used in HII DB
+///
+typedef enum {
+ UQI,
+ EN_US,
+ ENG
+} LANGUAGE;
+
+///
+/// Define the structure for the parameters of Uqi and Uqi List
+///
+typedef struct _FORM_BROWSER_STATEMENT FORM_BROWSER_STATEMENT;
+
+typedef enum {
+ ONE_OF,
+ NUMERIC,
+ CHECKBOX,
+ STRING,
+ ORDERED_LIST
+} QUEST_TYPE;
+
+typedef struct {
+ UINT16 *DefaultId;
+ UINT64 *PlatformId;
+ UINT32 IdNum;
+ UINT32 HexNum;
+ QUEST_TYPE Type;
+ CHAR16 *Data;
+ UINT8 *Value;
+ UINT8 *DiffValue;
+ UINT32 ScriptsLine;
+ FORM_BROWSER_STATEMENT *Question;
+} UQI_HEADER;
+
+typedef struct _UQI_PARAM_LIST {
+ struct _UQI_PARAM_LIST *Next;
+ UQI_HEADER Header;
+ BOOLEAN ParseOrNot;
+ BOOLEAN SameOrNot;
+ BOOLEAN ErrorOrNot;
+ CHAR8 *Error;
+} UQI_PARAM_LIST;
+
+//
+// Incremental size of stack for expression
+//
+#define EXPRESSION_STACK_SIZE_INCREMENT 0x100
+
+//
+// IFR relative definition
+//
+#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0
+#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1
+#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2
+#define EFI_HII_EXPRESSION_SUPPRESS_IF 3
+#define EFI_HII_EXPRESSION_DISABLE_IF 4
+#define EFI_HII_EXPRESSION_VALUE 5
+#define EFI_HII_EXPRESSION_RULE 6
+#define EFI_HII_EXPRESSION_READ 7
+#define EFI_HII_EXPRESSION_WRITE 8
+#define EFI_HII_EXPRESSION_WARNING_IF 9
+
+#define EFI_HII_VARSTORE_BUFFER 0
+#define EFI_HII_VARSTORE_NAME_VALUE 1
+#define EFI_HII_VARSTORE_EFI_VARIABLE 2
+#define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3
+
+#define FORM_INCONSISTENT_VALIDATION 0
+#define FORM_NO_SUBMIT_VALIDATION 1
+
+typedef struct {
+ //
+ // HII Data Type
+ //
+ UINT8 Type;
+ //
+ // Buffer Data and Length if Type is EFI_IFR_TYPE_BUFFER or EFI_IFR_TYPE_STRING
+ //
+ UINT8 *Buffer;
+ UINT16 BufferLen;
+ EFI_IFR_TYPE_VALUE Value;
+} EFI_HII_VALUE;
+
+#define NAME_VALUE_NODE_SIGNATURE SIGNATURE_32 ('N', 'V', 'S', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ CHAR16 *Name;
+ CHAR16 *Value;
+ CHAR16 *EditValue;
+} NAME_VALUE_NODE;
+
+#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE)
+
+#define FORMSET_STORAGE_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'G')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT64 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT32 DefaultPlatformIdNum;
+ UINT32 FormSetOrder;
+
+ BOOLEAN NewEfiVarstore; //EfiVarStore for UEFI 2.31 or not
+ BOOLEAN Skip; //Flag for sorting out the variables
+
+ UINT8 Type; // Storage type
+
+ UINT16 VarStoreId;
+ EFI_GUID Guid;
+
+ CHAR16 *Name; // For EFI_IFR_VARSTORE
+ UINT16 Size;
+ UINT8 *Buffer;
+
+ LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE
+
+ UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
+} FORMSET_STORAGE;
+
+#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE)
+
+typedef union {
+ EFI_STRING_ID VarName;
+ UINT16 VarOffset;
+} VAR_STORE_INFO;
+
+#define EXPRESSION_OPCODE_SIGNATURE SIGNATURE_32 ('E', 'X', 'O', 'P')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Operand;
+
+ UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND
+ UINT8 Flags; // For EFI_IFR_SPAN
+ UINT8 RuleId; // For EFI_IFR_RULE_REF
+
+ EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1
+
+ EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_VAL_LIST, EFI_IFR_QUESTION_REF1
+ EFI_QUESTION_ID QuestionId2;
+
+ UINT16 ListLength; // For EFI_IFR_EQ_ID_VAL_LIST
+ UINT16 *ValueList;
+
+ EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3
+ EFI_GUID Guid;
+
+ FORMSET_STORAGE *VarStorage; // For EFI_IFR_SET, EFI_IFR_GET
+ VAR_STORE_INFO VarStoreInfo;// For EFI_IFR_SET, EFI_IFR_GET
+ UINT8 ValueType; // For EFI_IFR_SET, EFI_IFR_GET
+ UINT8 ValueWidth; // For EFI_IFR_SET, EFI_IFR_GET
+ CHAR16 *ValueName; // For EFI_IFR_SET, EFI_IFR_GET
+ LIST_ENTRY MapExpressionList; // nested expressions inside of Map opcode.
+} EXPRESSION_OPCODE;
+
+#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE)
+
+#define FORM_EXPRESSION_SIGNATURE SIGNATURE_32 ('F', 'E', 'X', 'P')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Type; // Type for this expression
+
+ UINT8 RuleId; // For EFI_IFR_RULE only
+ EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only
+
+ EFI_HII_VALUE Result; // Expression evaluation result
+ UINT8 TimeOut; // For EFI_IFR_WARNING_IF
+
+ LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE)
+} FORM_EXPRESSION;
+
+#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE)
+
+#define QUESTION_DEFAULT_SIGNATURE SIGNATURE_32 ('Q', 'D', 'F', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId;
+ EFI_HII_VALUE Value; // Default value
+
+ FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE
+} QUESTION_DEFAULT;
+
+#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE)
+
+#define QUESTION_OPTION_SIGNATURE SIGNATURE_32 ('Q', 'O', 'P', 'T')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_STRING_ID Text;
+ UINT8 Flags;
+ EFI_HII_VALUE Value;
+
+ FORM_EXPRESSION *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf
+} QUESTION_OPTION;
+
+#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE)
+
+#define FORM_BROWSER_STATEMENT_SIGNATURE SIGNATURE_32 ('F', 'S', 'T', 'A')
+
+struct _FORM_BROWSER_STATEMENT {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINT8 Operand; // The operand (first byte) of this Statement or Question
+
+ UQI_HEADER Uqi;
+ UINT32 FormSetOrder;
+ EFI_GUID Guid;
+ UINT8 Type; // Storage type
+ BOOLEAN NewEfiVarstore; //EfiVarStore for UEFI 2.31 or not
+ UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
+ BOOLEAN QuestionReferToBitField;// Whether the question is stored in a bit field.
+ //
+ // Statement Header
+ //
+ EFI_STRING_ID Prompt;
+ EFI_STRING_ID Help;
+ EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT
+
+ //
+ // Question Header
+ //
+ EFI_QUESTION_ID QuestionId; // The value of zero is reserved
+ EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage
+ FORMSET_STORAGE *Storage;
+ VAR_STORE_INFO VarStoreInfo;
+ UINT16 StorageWidth;
+ UINT16 BitStorageWidth;
+ UINT16 BitVarOffset;
+ UINT8 QuestionFlags;
+ CHAR16 *VariableName; // Name/Value or EFI Variable name
+
+ EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof
+ UINT8 *BufferValue; // Edit copy for string, password, orderedlist
+ UINT8 ValueType; // Data type for orderedlist value array
+
+ //
+ // OpCode specific members
+ //
+ UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF,
+ // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER
+ UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST
+
+ UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number
+
+ UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value
+ UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length
+ UINT64 Step;
+
+ EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON
+ EFI_GUID RefreshGuid; // for EFI_IFR_REFRESH_ID
+
+ //
+ // Get from IFR parsing
+ //
+ FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly
+ LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values
+ LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION)
+
+ EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE
+ UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh
+ BOOLEAN InSubtitle; // nesting inside of EFI_IFR_SUBTITLE
+
+ LIST_ENTRY InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION)
+ LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION)
+ LIST_ENTRY WarningListHead; // nested warning expression list (FORM_EXPRESSION)
+ FORM_EXPRESSION *GrayOutExpression; // nesting inside of GrayOutIf
+ FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf
+ FORM_EXPRESSION *DisableExpression; // nesting inside of DisableIf
+
+ FORM_EXPRESSION *ReadExpression; // nested EFI_IFR_READ, provide this question value by read expression.
+ FORM_EXPRESSION *WriteExpression; // nested EFI_IFR_WRITE, evaluate write expression after this question value is set.
+};
+
+#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE)
+
+#define FORM_BROWSER_FORM_SIGNATURE SIGNATURE_32 ('F', 'F', 'R', 'M')
+#define STANDARD_MAP_FORM_TYPE 0x01
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 FormId; // FormId of normal form or formmap form.
+ EFI_STRING_ID FormTitle; // FormTile of normal form, or FormMapMethod title of formmap form.
+ UINT16 FormType; // Specific form type for the different form.
+
+ BOOLEAN ModalForm; // Whether this is a modal form.
+ LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
+ LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT)
+ FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf
+} FORM_BROWSER_FORM;
+
+#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE)
+
+#define FORMSET_DEFAULTSTORE_SIGNATURE SIGNATURE_32 ('F', 'D', 'F', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT16 DefaultId;
+ EFI_STRING_ID DefaultName;
+} FORMSET_DEFAULTSTORE;
+
+#define STRING_NUMBER 100
+
+typedef struct {
+ EFI_STRING_ID StringId;
+ CHAR16 *String;
+} STRING_INFO;
+
+typedef struct {
+ EFI_STRING_ID CachedIdNum;
+ EFI_STRING_ID MaxIdNum;
+ STRING_INFO *StringInfoList;
+} FORMSET_STRING_LIST;
+
+#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE)
+
+#define FORM_BROWSER_FORMSET_SIGNATURE SIGNATURE_32 ('F', 'B', 'F', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ UINT32 FormSetOrder;
+
+ UINTN IfrBinaryLength;
+ UINT8 *IfrBinaryData;
+ UINT8 *UnicodeBinary;
+
+ EFI_GUID Guid;
+ EFI_STRING_ID FormSetTitle;
+ EFI_STRING_ID Help;
+ UINT8 NumberOfClassGuid;
+ EFI_GUID ClassGuid[3]; // Up to three ClassGuid
+ UINT16 Class; // Tiano extended Class code
+ UINT16 SubClass; // Tiano extended Subclass code
+
+ FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions
+ EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode
+
+ LIST_ENTRY *StorageListHead; // Storage list (FORMSET_STORAGE)
+ LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE)
+ LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM)
+ LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION)
+ FORMSET_STRING_LIST EnUsStringList; // Cache EN_US English list
+ FORMSET_STRING_LIST UqiStringList; // Cache EN_US English list
+} FORM_BROWSER_FORMSET;
+
+#define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE)
+
+///
+/// Structure for multi-platform support
+///
+typedef struct {
+ UINT16 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 DefaultIdNum;
+ UINT64 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 PlatformIdNum;
+ UINT16 KeyDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT64 KeyPlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ UINT16 KeyIdNum;
+ FORM_BROWSER_STATEMENT PlatformIdQuestion;
+ FORM_BROWSER_STATEMENT *Question;
+ UINT16 PlatformIdWidth;
+ UQI_HEADER Uqi;
+ BOOLEAN MultiPlatformOrNot;
+ BOOLEAN ExistStorageFfsInBfv;
+ BOOLEAN SizeOptimized;
+ BOOLEAN SizeOptimizedParam;
+} MULTI_PLATFORM_PARAMETERS;
+
+/**
+ Search the variable list according to the variable Guid and name, and return the pointer
+ of that Node.
+
+ @param HiiObjList The pointer to the Question
+ @param VarName The EFI variable name need to be updated to VarList
+ @param Offset The offset of the variable
+ @param StorageListHead The pointer to the LIST_ENTRY of Storage
+ @param Vaue The value in that value offset of the variable
+ @param VarList The dual pointer of Varlist
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+SearchVarStorage (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN CHAR16* VarName,
+ IN UINT32 Offset,
+ IN LIST_ENTRY *StorageListHead,
+ IN OUT CHAR8 **Value,
+ IN OUT FORMSET_STORAGE **VarList
+ );
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+ IN EFI_STRING_ID Token,
+ IN UINT8 *UniPackge
+ );
+
+/**
+ Free resources allocated for all Storage in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllStorage (
+ IN LIST_ENTRY *StorageEntryListHead
+ );
+
+
+/**
+ Free resources allocated for a FormSet.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+
+/**
+ Free resources allocated for all FormSet in an LIST_ENTRY.
+
+ @param FormSet Pointer of the FormSet
+
+**/
+VOID
+DestroyAllFormSet (
+ IN LIST_ENTRY *FormSetEntryListHead
+ );
+
+/**
+ Parse opcodes in the formset IFR binary.
+
+ @param FormSet Pointer of the FormSet data structure.
+
+ @retval EFI_SUCCESS Opcode parse success.
+ @retval Other Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Set the value to the variable of platformId question.
+
+ @param PlatformId The form set.
+
+ @retval EFI_SUCCESS Set successfully.
+
+**/
+EFI_STATUS
+AssignThePlatformId (
+ IN UINT64 PlatformId
+ );
+
+
+/**
+ Reset Questions to their default value in a Form, Formset or System.
+
+ @param FormSet FormSet data structure.
+ @param Form Form data structure.
+ @param DefaultId The default Id
+ @param PlatformId The platform Id
+ @param SettingScope Setting Scope for Default action.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_UNSUPPORTED Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN UINT16 DefaultId,
+ IN UINT64 PlatformId,
+ IN BROWSER_SETTING_SCOPE SettingScope
+ );
+
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+ VOID
+ );
+
+
+/**
+ Push current expression onto the Stack
+
+ @param Pointer Pointer to current expression.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+ IN VOID *Pointer
+ );
+
+
+/**
+ Pop current expression from the Stack
+
+ @param Pointer Pointer to current expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+ OUT VOID **Pointer
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+ VOID
+ );
+
+
+/**
+ Push the list of map expression onto the Stack
+
+ @param Pointer Pointer to the list of map expression to be pushed.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+ IN VOID *Pointer
+ );
+
+
+/**
+ Pop the list of map expression from the Stack
+
+ @param Pointer Pointer to the list of map expression to be pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+ OUT VOID **Pointer
+ );
+
+/**
+ Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+ VOID
+ );
+
+
+/**
+ Push an Operand onto the Stack
+
+ @param Operand Operand to push.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PushScope (
+ IN UINT8 Operand
+ );
+
+
+/**
+ Pop an Operand from the Stack
+
+ @param Operand Operand to pop.
+
+ @retval EFI_SUCCESS The value was pushed onto the stack.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+
+**/
+EFI_STATUS
+PopScope (
+ OUT UINT8 *Operand
+ );
+
+
+/**
+ Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+ @param Value HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+ IN EFI_HII_VALUE *Value
+ );
+
+
+/**
+ Compare two Hii value.
+
+ @param Value1 Expression value to compare on left-hand.
+ @param Value2 Expression value to compare on right-hand.
+
+ @retval EFI_INVALID_PARAMETER Could not perform compare on two values.
+ @retval 0 Two operators equal.
+ @return Positive value if Value1 is greater than Value2.
+ @retval Negative value if Value1 is less than Value2.
+
+**/
+INTN
+CompareHiiValue (
+ IN EFI_HII_VALUE *Value1,
+ IN EFI_HII_VALUE *Value2,
+ IN FORM_BROWSER_FORMSET *FormSet
+ );
+
+/**
+ Evaluate the result of a HII expression.
+
+ If Expression is NULL, then ASSERT.
+
+ @param FormSet FormSet associated with this expression.
+ @param Form Form associated with this expression.
+ @param Expression Expression to be evaluated.
+ @param ConstantExpression The pointer to the flag of constant expression. If constant, will return TRUE.
+
+ @retval EFI_SUCCESS The expression evaluated successfuly
+ @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
+ could not be found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
+ stack.
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
+ @retval EFI_INVALID_PARAMETER Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+ IN FORM_BROWSER_FORMSET *FormSet,
+ IN FORM_BROWSER_FORM *Form,
+ IN OUT FORM_EXPRESSION *Expression,
+ IN OUT BOOLEAN *ConstantExpression
+ );
+
+/**
+ Compare two Uqi parameters
+
+ @param UqiParm1 The pointer to the first Uqi parameter.
+ @param UqiParm2 The pointer to the second Uqi parameter.
+
+ @retval TRUE If these two Uqi parameters are the same, return TRUE;
+ @return FALSE Otherwise, return FALSE;
+**/
+BOOLEAN
+CompareUqiHeader (
+ IN CONST UQI_HEADER *UqiParm1,
+ IN CONST UQI_HEADER *UqiParm2
+ );
+
+
+/**
+ Print all ONE_OF ORDER_LIST NUMERIC STRING and CHECKBOX in all fromsets.
+
+ @param Formset The pointer to the entry of the fromset list
+ @param Formset The pointer to the entry of the storage list
+
+ @retval EFI_SUCCESS It was complete successfully
+ @return EFI_ABORTED An error occurred
+**/
+EFI_STATUS
+PrintInfoInAllFormset (
+ IN LIST_ENTRY *FormSetEntryListHead,
+ IN LIST_ENTRY *StorageEntryListHead
+ );
+
+ /**
+ Get the question value with bit field from the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value get from.
+ @param Value Retun the value.
+
+**/
+VOID
+GetBitsQuestionValue(
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT8 *Buffer,
+ OUT UINT32 *Value
+ );
+
+/**
+ Set the question value with bit field to the buffer.
+
+ @param Question The question refer to bit field.
+ @param Buffer The buffer which the question value set to.
+ @param Value The value need to set.
+
+**/
+VOID
+SetBitsQuestionValue (
+ IN FORM_BROWSER_STATEMENT *Question,
+ IN UINT8 *Buffer,
+ IN UINT32 Value
+ );
+
+#endif
diff --git a/Platform/Intel/Tools/FCE/Makefile b/Platform/Intel/Tools/FCE/Makefile
new file mode 100644
index 0000000000..c8a025e27f
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Makefile
@@ -0,0 +1,19 @@
+## @file
+#
+# Windows makefile for 'FCE' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = FCE
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = Fce.obj Variable.obj TimeBasedVariable.obj MonotonicBasedVariable.obj IfrParse.obj Common.obj BinaryParse.obj BinaryCreate.obj Expression.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
diff --git a/Platform/Intel/Tools/FCE/MonotonicBasedVariable.c b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
new file mode 100644
index 0000000000..9d35bffab6
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
@@ -0,0 +1,874 @@
+/** @file
+
+ Read and edit the authenticated variables.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "MonotonicBasedVariable.h"
+
+extern LIST_ENTRY mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern G_EFI_FD_INFO gEfiFdInfo;
+EFI_GUID gEfiAuthenticatedVariableGuid = EFI_AUTHENTICATED_VARIABLE_GUID;
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+}
+
+/**
+
+ This code gets the size of variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+}
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable);
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return (UINT8 *) Value;
+}
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ if (!IsValidVariableHeader (Variable)) {
+ return NULL;
+ }
+
+ Value = (UINTN) GetVariableDataPtr (Variable);
+ Value += DataSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+ Search and get a free space in the EFI variable zone
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarListSize The size of a variables needs to be allocated.
+ @param FreeBeginVar The dual pointer to the free NV space.
+
+ @retval EFI_SUCCESS Return the beginning of a free variable space.
+ @retval RETURN_BUFFER_TOO_SMALL Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN UINT32 VarListSize,
+ IN OUT CHAR8 **FreeBeginVar
+)
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR8 *BeginVar;
+
+ BeginVar = NULL;
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ *FreeBeginVar = NULL;
+
+ if (VariableStoreHeader == NULL) {
+ *FreeBeginVar = NULL;
+ return RETURN_INVALID_PARAMETER;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ //Search the beginning of free NV
+ //
+ while (Variable != EndOfVariable) {
+ BeginVar = (CHAR8 *)Variable;
+ Variable = GetNextVariablePtr (Variable);
+ if (Variable == NULL) {
+ Flag = TRUE;
+ break;
+ }
+ }
+ //
+ // Check whether the free space is more than what we want
+ //
+ if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ //
+ // If not find the available space, return NULL
+ //
+ if (!Flag) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ *FreeBeginVar = BeginVar;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search whether the variable in VarList has existed in current NV.
+
+ Parse the FFS or Fd image, and find the valid variable pointer.
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarList The pointer to the VarList
+
+ @retval address If the variable existed in current NV, return address
+ @return NULL Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER *
+FindVariableInNv (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR16 *VariableName;
+
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ VariableName = NULL;
+
+ if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+ return NULL;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ // Parse and compare the variable in the NV space one by one
+ //
+ while ((Variable != EndOfVariable) && (Variable != NULL)) {
+ VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+ if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+ && !FceStrCmp (Storage->Name, VariableName) \
+ && (Variable->State == VAR_ADDED)) {
+ Flag = TRUE;
+ break;
+ }
+ Variable = GetNextVariablePtr (Variable);
+ }
+ if (!Flag) {
+ return NULL;
+ }
+ return Variable;
+}
+
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+EFI_STATUS
+SynAuthEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ CHAR8 *DataBase;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+
+ Status = EFI_SUCCESS;
+ DataBase = NULL;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if (VarToList) {
+ //
+ //Copy the data from NV to the VarList.
+ //
+ if (VariableHeader != NULL) {
+ if (Storage->Buffer == NULL) {
+ Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ ASSERT (Storage->Buffer != NULL);
+ }
+ //
+ // The variable in VarList is CHAR8, but in the EFI variable is CHAR16.
+ //
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ Storage->Buffer,
+ (VOID *) DataBase,
+ Storage->Size
+ );
+ }
+ } else {
+ //
+ //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ //
+ //If this variable has existed in current FD, the data in VarList has
+ // been updated, and this variable is not authenticated type, then
+ // update it from VarList to the FD.
+ //
+ if ((VariableHeader != NULL) \
+ && (Storage->Buffer != NULL)
+ ) {
+ if (!(VariableHeader->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)) {
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ (VOID *) DataBase,
+ Storage->Buffer,
+ Storage->Size
+ );
+ } else {
+ printf ("Error. Not support to update authenticated variables.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+ //
+ //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+ //
+ if (Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Try to get the available zone from the efi variables
+ //
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create the authenticated variable header
+ //
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ VariableHeader->PubKeyIndex = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ } else {
+ printf ("Error. No available space in NV ram.\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return Status;
+}
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+ if (VariableHeader != NULL) {
+ VariableHeader->State = VAR_DELETED;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the store variable is Monotonic based authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckMonotonicBasedVarStore (
+ IN VOID *VariableStoreHeader
+ )
+{
+ if (!CompareGuid (
+ &gEfiAuthenticatedVariableGuid,
+ &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Copy Monotonic-Based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyMonotonicBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiAuthenticatedVariableGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ VariableHeader->PubKeyIndex = 0x0;
+
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+
+
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+
+
+/**
+ Read Monotonic-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadMonotonicBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN ReadIdHeaderFlag;
+ UINT32 Length;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ static UINT64 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ ReadIdHeaderFlag = TRUE;
+ Length = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)Binary;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // If access the first storage, read the platformId and defaultId
+ //
+ if (ReadIdHeaderFlag) {
+ ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+ ReadIdHeaderFlag = FALSE;
+ memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ } else {
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ }
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ }
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+ return Length;
+}
+
+/**
+ Check whether exists the valid MonotonicBased variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistMonotonicBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if ((Storage->Buffer == NULL)
+ || (Storage->Name == NULL)
+ || (FceStrLen(Storage->Name) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if ((VariableHeader != NULL)) {
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return FALSE;
+}
+/**
+ Fix the size of montonic variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixMontonicVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+ VariableStoreHeader->Size = Length - *(UINT16 *)BinaryBeginning;
+}
diff --git a/Platform/Intel/Tools/FCE/MonotonicBasedVariable.h b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
new file mode 100644
index 0000000000..11fc51ed38
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
@@ -0,0 +1,162 @@
+/** @file
+
+ The header of MonotonicBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_H__
+
+#define EFI_AUTHENTICATED_VARIABLE_GUID \
+ { 0x515fa686, 0xb06e, 0x4550, { 0x91, 0x12, 0x38, 0x2b, 0xf1, 0x6, 0x7b, 0xfb }}
+
+extern EFI_GUID gEfiAuthenticatedVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1
+/// * For IA-64 architecture: 8
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT 8
+#else
+#define ALIGNMENT 1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition
+#define VAR_DELETED 0xfd ///< Variable is obsolete
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid
+#define VAR_ADDED 0x3f ///< Variable has been completely added
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI spec
+ ///
+ UINT32 Attributes;
+ ///
+ /// Associated monotonic count value against replay attack.
+ ///
+ UINT64 MonotonicCount;
+ ///
+ /// Index of associated public key in database.
+ ///
+ UINT32 PubKeyIndex;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI spec.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/Platform/Intel/Tools/FCE/TimeBasedVariable.c b/Platform/Intel/Tools/FCE/TimeBasedVariable.c
new file mode 100644
index 0000000000..e21c61dde9
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/TimeBasedVariable.c
@@ -0,0 +1,878 @@
+/** @file
+
+ Read and edit the time-base authenticated variables.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "TimeBasedVariable.h"
+
+extern LIST_ENTRY mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern G_EFI_FD_INFO gEfiFdInfo;
+
+EFI_GUID gEfiAuthenticatedVariableBasedTimeGuid = EFI_AUTHENTICATED_VARIABLE_BASED_TIME_GUID;
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+}
+
+/**
+
+ This code gets the size of variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+}
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable);
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return (UINT8 *) Value;
+}
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ if (!IsValidVariableHeader (Variable)) {
+ return NULL;
+ }
+
+ Value = (UINTN) GetVariableDataPtr (Variable);
+ Value += DataSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+ Search and get a free space in the EFI variable zone
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarListSize The size of a variables needs to be allocated.
+ @param FreeBeginVar The dual pointer to the free NV space.
+
+ @retval EFI_SUCCESS Return the beginning of a free variable space.
+ @retval RETURN_BUFFER_TOO_SMALL Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN UINT32 VarListSize,
+ IN OUT CHAR8 **FreeBeginVar
+)
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR8 *BeginVar;
+
+ BeginVar = NULL;
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ *FreeBeginVar = NULL;
+
+ if (VariableStoreHeader == NULL) {
+ *FreeBeginVar = NULL;
+ return RETURN_INVALID_PARAMETER;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ //Search the beginning of free NV
+ //
+ while (Variable != EndOfVariable) {
+ BeginVar = (CHAR8 *)Variable;
+ Variable = GetNextVariablePtr (Variable);
+ if (Variable == NULL) {
+ Flag = TRUE;
+ break;
+ }
+ }
+ //
+ // Check whether the free space is more than what we want
+ //
+ if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ //
+ // If not find the available space, return NULL
+ //
+ if (!Flag) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ *FreeBeginVar = BeginVar;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search whether the variable in VarList has existed in current NV.
+
+ Parse the FFS or Fd image, and find the valid variable pointer.
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarList The pointer to the VarList
+
+ @retval address If the variable existed in current NV, return address
+ @return NULL Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER *
+FindVariableInNv (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR16 *VariableName;
+
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ VariableName = NULL;
+
+ if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+ return NULL;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ // Parse and compare the variable in the NV space one by one
+ //
+ while ((Variable != EndOfVariable) && (Variable != NULL)) {
+ VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+ if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+ && !FceStrCmp (Storage->Name, VariableName) \
+ && (Variable->State == VAR_ADDED)
+ ) {
+ Flag = TRUE;
+ break;
+ }
+ Variable = GetNextVariablePtr (Variable);
+ }
+ if (!Flag) {
+ return NULL;
+ }
+ return Variable;
+}
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the time stamp authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+ @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+
+EFI_STATUS
+SynAuthEfiVariableBasedTime (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ CHAR8 *DataBase;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+
+ Status = EFI_SUCCESS;
+ DataBase = NULL;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if (VarToList) {
+ //
+ //Copy the data from NV to the VarList.
+ //
+ if (VariableHeader != NULL) {
+ if (Storage->Buffer == NULL) {
+ Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ ASSERT (Storage->Buffer != NULL);
+ }
+ //
+ // The variable in VarList is CHAR8, but in the EFI variable is CHAR16.
+ //
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ Storage->Buffer,
+ (VOID *) DataBase,
+ Storage->Size
+ );
+ }
+ } else {
+ //
+ //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ //
+ //If this variable has existed in current FD, the data in VarList has
+ // been updated, and this variable is not authenticated type, then
+ // update it from VarList to the FD.
+ //
+ if ((VariableHeader != NULL) \
+ && (Storage->Buffer != NULL)
+ ) {
+ if (!(VariableHeader->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)) {
+ DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ (VOID *) DataBase,
+ Storage->Buffer,
+ Storage->Size
+ );
+ } else {
+ printf ("Error. Not support to update authenticated variables.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+ //
+ //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+ //
+ if (Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Try to get the available zone from the efi variables
+ //
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create the authenticated variable header
+ //
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ memset (&(VariableHeader->TimeStamp), 0, sizeof (EFI_TIME));
+ VariableHeader->PubKeyIndex = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ } else {
+ printf ("Error. No available space in NV ram.\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return Status;
+}
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariableBasedTime (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+ if (VariableHeader != NULL) {
+ VariableHeader->State = VAR_DELETED;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the store variable is Time stamp authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckTimeBasedVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ )
+{
+ if (!CompareGuid (
+ &gEfiAuthenticatedVariableBasedTimeGuid,
+ &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Copy time-based authenticated variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyTimeBasedVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiAuthenticatedVariableBasedTimeGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ VariableHeader->MonotonicCount = 0x0;
+ memset (&(VariableHeader->TimeStamp), 0, sizeof (EFI_TIME));
+ VariableHeader->PubKeyIndex = 0x0;
+
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+
+/**
+ Read time-based authenticated variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadTimeBasedVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN ReadIdHeaderFlag;
+ UINT32 Length;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ static UINT64 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ ReadIdHeaderFlag = TRUE;
+ Length = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)Binary;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // If access the first storage, read the platformId and defaultId
+ //
+ if (ReadIdHeaderFlag) {
+ ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+ ReadIdHeaderFlag = FALSE;
+ memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ } else {
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ }
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ }
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+ return Length;
+}
+
+/**
+ Check whether exists the valid time-based variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistTimeBasedEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if ((Storage->Buffer == NULL)
+ || (Storage->Name == NULL)
+ || (FceStrLen(Storage->Name) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if ((VariableHeader != NULL)) {
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return FALSE;
+}
+
+/**
+ Fix the size of time-based variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixBasedTimeVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+ VariableStoreHeader->Size = Length - *(UINT16 *)BinaryBeginning;
+}
diff --git a/Platform/Intel/Tools/FCE/TimeBasedVariable.h b/Platform/Intel/Tools/FCE/TimeBasedVariable.h
new file mode 100644
index 0000000000..3ffd939443
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/TimeBasedVariable.h
@@ -0,0 +1,166 @@
+/** @file
+
+ The header of TimeBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_BASED_TIME_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_BASED_TIME_H__
+
+#define EFI_AUTHENTICATED_VARIABLE_BASED_TIME_GUID \
+ { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
+
+extern EFI_GUID gEfiAuthenticatedVariableBasedTimeGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1
+/// * For IA-64 architecture: 8
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT 8
+#else
+#define ALIGNMENT 1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition
+#define VAR_DELETED 0xfd ///< Variable is obsolete
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid
+#define VAR_ADDED 0x3f ///< Variable has been completely added
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI spec
+ ///
+ UINT32 Attributes;
+ ///
+ /// Associated monotonic count value against replay attack.
+ ///
+ UINT64 MonotonicCount;
+ ///
+ /// Associated TimeStamp value against replay attack.
+ ///
+ EFI_TIME TimeStamp;
+ ///
+ /// Index of associated public key in database.
+ ///
+ UINT32 PubKeyIndex;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI spec.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/Platform/Intel/Tools/FCE/Variable.c b/Platform/Intel/Tools/FCE/Variable.c
new file mode 100644
index 0000000000..5c92060309
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Variable.c
@@ -0,0 +1,1091 @@
+/** @file
+
+ Read and edit the EFI variable.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "Variable.h"
+
+extern LIST_ENTRY mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS mMultiPlatformParam;
+extern G_EFI_FD_INFO gEfiFdInfo;
+
+EFI_GUID gEfiVariableGuid = EFI_VARIABLE_GUID;
+/**
+
+ Gets the pointer to the first variable header in given variable store area.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+ Gets the pointer to the end of the variable storage area.
+
+ This function gets pointer to the end of the variable storage
+ area, according to the input variable store header.
+
+ @param VarStoreHeader Pointer to the Variable Store Header.
+
+ @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ //
+ // The end of variable store
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+ This code checks if variable header is valid or not.
+
+ @param Variable Pointer to the Variable Header.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ This code gets the size of name of variable.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return UINTN Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+}
+
+/**
+
+ This code gets the size of variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ if ((Variable->State == (UINT8) (-1)) ||
+ (Variable->DataSize == (UINT32) (-1)) ||
+ (Variable->NameSize == (UINT32) (-1)) ||
+ (Variable->Attributes == (UINT32) (-1))
+ ) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+}
+
+/**
+
+ This code gets the pointer to the variable name.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+
+ return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+ This code gets the pointer to the variable data.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ Value = (UINTN) GetVariableNamePtr (Variable);
+ Value += NameSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+ return (UINT8 *) Value;
+}
+
+/**
+
+ This code gets the pointer to the next variable header.
+
+ @param Variable Pointer to the Variable Header.
+
+ @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+ IN VARIABLE_HEADER *Variable
+ )
+{
+ UINTN Value;
+
+ if (!IsValidVariableHeader (Variable)) {
+ return NULL;
+ }
+
+ Value = (UINTN) GetVariableDataPtr (Variable);
+ Value += DataSizeOfVariable (Variable);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+ //
+ // Be careful about pad size for alignment.
+ //
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+ Search and get a free space in the EFI variable zone
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarListSize The size of a variables needs to be allocated.
+ @param FreeBeginVar The dual pointer to the free NV space.
+
+ @retval EFI_SUCCESS Return the beginning of a free variable space.
+ @retval RETURN_BUFFER_TOO_SMALL Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN UINT32 VarListSize,
+ IN OUT CHAR8 **FreeBeginVar
+)
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR8 *BeginVar;
+
+ BeginVar = NULL;
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ *FreeBeginVar = NULL;
+
+ if (VariableStoreHeader == NULL) {
+ *FreeBeginVar = NULL;
+ return RETURN_INVALID_PARAMETER;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ //Search the beginning of free NV
+ //
+ while (Variable != EndOfVariable) {
+ BeginVar = (CHAR8 *)Variable;
+ Variable = GetNextVariablePtr (Variable);
+ if (Variable == NULL) {
+ Flag = TRUE;
+ break;
+ }
+ }
+ //
+ // Check whether the free space is more than what we want
+ //
+ if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ //
+ // If not find the available space, return NULL
+ //
+ if (!Flag) {
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ *FreeBeginVar = BeginVar;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search whether the variable in VarList has existed in current NV.
+
+ Parse the FFS or Fd image, and find the valid variable pointer.
+
+ @param VariableStoreHeader The start of a EFI variable zone.
+ @param VarList The pointer to the VarList
+
+ @retval address If the variable existed in current NV, return address
+ @return NULL Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER *
+FindVariableInNv (
+ IN VARIABLE_STORE_HEADER *VariableStoreHeader,
+ IN FORMSET_STORAGE *Storage
+ )
+{
+ BOOLEAN Flag;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_HEADER *EndOfVariable;
+ CHAR16 *VariableName;
+
+ Flag = FALSE;
+ Variable = NULL;
+ EndOfVariable = NULL;
+ VariableName = NULL;
+
+ if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+ return NULL;
+ }
+ Variable = GetStartPointer (VariableStoreHeader);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+ //
+ // Parse and compare the variable in the NV space one by one
+ //
+ while ((Variable != EndOfVariable) && (Variable != NULL)) {
+ VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+ if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+ && !FceStrCmp (Storage->Name, VariableName) \
+ && (Variable->State == VAR_ADDED)) {
+ Flag = TRUE;
+ break;
+ }
+ Variable = GetNextVariablePtr (Variable);
+ }
+ if (!Flag) {
+ return NULL;
+ }
+ return Variable;
+}
+/**
+ Exchange the data between Efi variable and the data of VarList when the
+ variable use the authenticated variable header
+
+ If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+ update the data from varlist to efi variable.
+
+ @param VarToList The flag to control the direction of exchange.
+ @param StorageListHead Decide which variale list be updated
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_OUT_OF_RESOURCES No available in the EFI variable zone.
+**/
+
+EFI_STATUS
+SynEfiVariable (
+ IN BOOLEAN VarToList,
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ CHAR8 *DataBase;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+
+ Status = EFI_SUCCESS;
+ DataBase = NULL;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if (VarToList) {
+ //
+ //Copy the data from NV to the VarList.
+ //
+ if (VariableHeader != NULL) {
+ if (Storage->Buffer == NULL) {
+ Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+ ASSERT (Storage->Buffer != NULL);
+ }
+ DataBase = (CHAR8*)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ Storage->Buffer,
+ (VOID *) DataBase,
+ Storage->Size
+ );
+ }
+ } else {
+ //
+ //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ //
+ //If this variable has existed in current FD, the data in VarList has
+ // been updated, and this variable is not authenticated type, then
+ // update it from VarList to the FD.
+ //
+ if ((VariableHeader != NULL) \
+ && (Storage->Buffer != NULL)
+ ) {
+ DataBase = (CHAR8*)GetVariableDataPtr (VariableHeader);
+ memcpy (
+ (VOID *) DataBase,
+ Storage->Buffer,
+ Storage->Size
+ );
+ } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+ //
+ //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+ //
+ if (Storage->NewEfiVarstore
+ && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Try to get the available zone from the efi variables
+ //
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create the variable header
+ //
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ } else {
+ printf ("Error. No available space in NV ram.\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return Status;
+}
+
+/**
+ Remove the variable from Efi variable
+
+ Found the variable with the same name in StorageListHead and remove it.
+
+ @param StorageListHead Decide which variale list be removed.
+
+ @retval EFI_SUCCESS Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveNormalEfiVariable (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if (Storage->Buffer == NULL) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return EFI_INVALID_PARAMETER;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+ if (VariableHeader != NULL) {
+ VariableHeader->State = VAR_DELETED;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the store variable is no-authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If no-authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckNormalVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ )
+{
+ if (!CompareGuid (
+ &gEfiVariableGuid,
+ &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiVariableGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+/**
+ Copy variable to binary in multi-platform mode
+
+ @param Storage The pointer to a storage in storage list.
+ @param StorageBeginning The pointer to the beginning of storage under specifed platformId and defaultId
+ @param Index The number of the storage. If the Index is 0, record the variable header to
+ the binary. Or else, only record the storage.
+
+ @return length The length of storage
+**/
+UINT32
+CopyVariableToNvStoreBinary (
+ IN FORMSET_STORAGE *Storage,
+ IN OUT UINT8 *StorageBeginning,
+ IN UINT32 Index
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *NewAvailableAddr;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VarNameSize;
+ UINT32 HeaderLength;
+ PCD_DEFAULT_DATA *PcdDefaultDataHeader;
+
+ Status = EFI_SUCCESS;
+ NewAvailableAddr = NULL;
+ VarNameSize = 0;
+ HeaderLength = 0;
+ VariableHeader = NULL;
+ VariableStoreHeader = NULL;
+
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ printf ("Error. One variable name is NULL. Its GUID is: ");
+ PrintGuid(&(Storage->Guid));
+ return 0;
+ }
+ //
+ // If the first storage under one specified platformId and defaultId, create the variable header
+ //
+ if (Index == 0) {
+ HeaderLength = WriteNvStoreDefaultAndPlatformId (StorageBeginning, Storage);
+ PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)StorageBeginning;
+ PcdDefaultDataHeader->HeaderSize = HeaderLength;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength + 4);
+ //
+ //Create the Variable Storage header
+ //
+ memcpy (&(VariableStoreHeader->Signature), &gEfiVariableGuid, sizeof (EFI_GUID));
+ VariableStoreHeader->Format = 0x5A;
+ VariableStoreHeader->State = 0xFE;
+ //
+ //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+ //
+ VariableStoreHeader->Size = gEfiFdInfo.FdSize;
+ }
+ PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)StorageBeginning;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + PcdDefaultDataHeader->HeaderSize + 4);
+ Status = GetVariableVar (
+ VariableStoreHeader,
+ Storage->Size + sizeof (VARIABLE_HEADER),
+ &NewAvailableAddr
+ );
+ if (EFI_ERROR (Status)) {
+ return FAIL;
+ }
+ //
+ // Create the variable header
+ //
+ VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+ VariableHeader = (VARIABLE_HEADER *) NewAvailableAddr;
+ VariableHeader->StartId = VARIABLE_DATA;
+ VariableHeader->State = VAR_ADDED;
+ VariableHeader->Reserved = 0x0;
+ if (Storage->NewEfiVarstore) {
+ VariableHeader->Attributes = Storage->Attributes;
+ } else {
+ VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+ VariableHeader->NameSize = VarNameSize;
+ VariableHeader->DataSize = Storage->Size;
+ //
+ //Copy the Guid, variable name, and data in sequence.
+ //
+ memcpy (
+ (VOID *)&(VariableHeader->VendorGuid),
+ &(Storage->Guid),
+ sizeof (EFI_GUID)
+ );
+
+ NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Name,
+ VarNameSize
+ );
+
+ NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ memcpy (
+ (VOID *) NewAvailableAddr,
+ Storage->Buffer,
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning - PcdDefaultDataHeader->HeaderSize - 4) + Storage->Size);
+}
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadNvStoreVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ UINT32 Length;
+ PCD_DEFAULT_DATA *PcdDefaultData;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId;
+ static UINT64 PrePlatformId;
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ Length = 0;
+ DataBase = Binary;
+
+ PcdDefaultData = (PCD_DEFAULT_DATA *)DataBase;
+ PrePlatformId = PcdDefaultData->DefaultInfo[0].SkuId;
+ PreDefaultId = PcdDefaultData->DefaultInfo[0].DefaultId;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + PcdDefaultData->HeaderSize + 4);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ Storage->DefaultId[0] = PreDefaultId;
+ Storage->PlatformId[0] = PrePlatformId;
+ Storage->DefaultPlatformIdNum = 0;
+
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ if (!IsValidVariableHeader(Variable)) {
+ break;
+ }
+ }
+
+ return Length;
+}
+/**
+ Read variable to storage list in multi-platform mode
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param StorageListEntry The pointer to the storage list.
+
+ @return length The length of storage
+**/
+UINT32
+ReadVariableToList (
+ IN UINT8 *Binary,
+ IN LIST_ENTRY *StorageListEntry
+ )
+{
+ VARIABLE_HEADER *EndOfVariable;
+ VARIABLE_HEADER *Variable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ FORMSET_STORAGE *Storage;
+ BOOLEAN ReadIdHeaderFlag;
+ UINT32 Length;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ UINT8 *DataBase;
+ static UINT16 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+ static UINT64 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+ VariableStoreHeader = NULL;
+ Variable = NULL;
+ ReadIdHeaderFlag = TRUE;
+ Length = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)Binary;
+ DataBase = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+ EndOfVariable = GetEndPointer(VariableStoreHeader);
+
+ for (Variable = GetStartPointer (VariableStoreHeader);
+ Length < VariableStoreHeader->Size;
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+ ) {
+ //
+ // Create the storage
+ //
+ Storage = NULL;
+ Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+ if (Storage == NULL) {
+ printf ("Allocate memory failed.\n");
+ return FAIL;
+ }
+ //
+ // If access the first storage, read the platformId and defaultId
+ //
+ if (ReadIdHeaderFlag) {
+ ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+ Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+ ReadIdHeaderFlag = FALSE;
+ memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ } else {
+ //
+ // Store the DefaultId and PlatformId collected from the header to Storage.
+ //
+ memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+ memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+ }
+ Storage->Attributes = Variable->Attributes;
+ Storage->Size = (UINT16)Variable->DataSize;
+ Storage->Name = calloc (Variable->NameSize, sizeof (UINT8));
+ ASSERT (Storage->Name != NULL);
+ Storage->Buffer = calloc (Variable->DataSize, sizeof (UINT8));
+ ASSERT (Storage->Buffer != NULL);
+ memcpy (
+ &(Storage->Guid),
+ &(Variable->VendorGuid),
+ sizeof (EFI_GUID)
+ );
+ memcpy (
+ Storage->Name,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+ Variable->NameSize
+ );
+ memcpy (
+ Storage->Buffer,
+ (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+ Storage->Size * sizeof (CHAR8)
+ );
+ //
+ // Assigned the value for comparison in verify mode
+ //
+ Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+ Storage->NewEfiVarstore = TRUE;
+ InitializeListHead (&Storage->NameValueListHead);
+
+ InsertTailList(StorageListEntry, &Storage->Link);
+ //
+ // If the last variable, exit.
+ //
+ if (Variable == EndOfVariable) {
+ break;
+ }
+
+ Variable = GetNextVariablePtr (Variable);
+ assert (Variable != NULL);
+ }
+ //
+ // Return the length which is from the beginning of Binary
+ //
+ Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+ return Length;
+}
+
+/**
+ Check whether exists the valid normal variables in NvStorage or not.
+
+ @retval TRUE If existed, return TRUE.
+ @retval FALSE Others
+**/
+BOOLEAN
+ExistNormalEfiVarOrNot (
+ IN LIST_ENTRY *StorageListHead
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
+ LIST_ENTRY *StorageLink;
+ FORMSET_STORAGE *Storage;
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableHeader = NULL;
+ VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+ //
+ //Parse the variable range, and check whether there is some existed ones.
+ //
+ StorageLink = GetFirstNode (StorageListHead);
+ while (!IsNull (StorageListHead, StorageLink)) {
+ Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+ //
+ // Ignore the invalid varlist node
+ //
+ if ((Storage->Buffer == NULL)
+ || (Storage->Name == NULL)
+ || (FceStrLen(Storage->Name) == 0)
+ ) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ //
+ // Report error, if the variable name is invalid.
+ //
+ if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ continue;
+ }
+ VariableHeader = FindVariableInNv (
+ VariableStoreHeader,
+ Storage
+ );
+
+ if ((VariableHeader != NULL)) {
+ return TRUE;
+ }
+ StorageLink = GetNextNode (StorageListHead, StorageLink);
+ }
+ return FALSE;
+}
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+ VariableStoreHeader->Size = Length - *(UINT16 *)BinaryBeginning;
+}
+
+/**
+ Fix the size of variable header.
+
+ @param Binary The pointer to the header of storage under specifed platformId and defaultId
+ @param Length The length of binary.
+
+**/
+VOID
+FixNvStoreVariableHeaderSize (
+ IN UINT8 *BinaryBeginning,
+ IN UINT32 Length
+ )
+{
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ PCD_DEFAULT_DATA *PcdDefaultDataHeader;
+
+ PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)(BinaryBeginning);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (BinaryBeginning + PcdDefaultDataHeader->HeaderSize + 4);
+ VariableStoreHeader->Size = Length;
+ PcdDefaultDataHeader->DataSize = VariableStoreHeader->Size + PcdDefaultDataHeader->HeaderSize + 4;
+}
+
diff --git a/Platform/Intel/Tools/FCE/Variable.h b/Platform/Intel/Tools/FCE/Variable.h
new file mode 100644
index 0000000000..35b88e045c
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Variable.h
@@ -0,0 +1,154 @@
+/** @file
+
+ The header of Variable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_FORMAT_H__
+#define __VARIABLE_FORMAT_H__
+
+#define EFI_VARIABLE_GUID \
+ { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } }
+
+extern EFI_GUID gEfiVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1.
+/// * For IA-64 architecture: 8.
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT 8
+#else
+#define ALIGNMENT 1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region.
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region.
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State.
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header.
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags.
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition.
+#define VAR_DELETED 0xfd ///< Variable is obsolete.
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid.
+#define VAR_ADDED 0x3f ///< Variable has been completely added.
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI specification.
+ ///
+ UINT32 Attributes;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI specification.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/Platform/Intel/Tools/FCE/VariableCommon.h b/Platform/Intel/Tools/FCE/VariableCommon.h
new file mode 100644
index 0000000000..7389902076
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/VariableCommon.h
@@ -0,0 +1,55 @@
+/** @file
+
+ The header of common Variable.c TimeBasedVariable.c and MonotonicBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_COMMON_H__
+#define __VARIABLE_COMMON_H__
+
+/**
+ Check the store variable is no-authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If no-authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckNormalVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ );
+/**
+ Check the store variable is Monotonic based authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckMonotonicBasedVarStore (
+ IN VOID *VariableStoreHeader
+ );
+
+/**
+ Check the store variable is Time stamp authenticated or not
+
+ @param VarToList The pointer to the header of Variable Store.
+
+ @retval TRUE If authenticated, return TRUE.
+ @retval FALSE Otherwise, return FALSE.
+**/
+BOOLEAN
+CheckTimeBasedVarStoreOrNot (
+ IN VOID *VariableStoreHeader
+ );
+
+
+
+#endif // _EFI_VARIABLE_COMMON_H_
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [edk2-platform patch 4/6] Platform\Tools: Add top level Makefile and GNUMakefile
2019-06-21 1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
` (2 preceding siblings ...)
2019-06-21 1:26 ` [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE Zhang, Shenglei
@ 2019-06-21 1:26 ` Zhang, Shenglei
2019-06-21 1:26 ` [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Zhang, Shenglei
` (2 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21 1:26 UTC (permalink / raw)
To: devel; +Cc: Bob Feng, Liming Gao
Add FMMT, BfmLib and FCE into Makefile and GNUMakefile.
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
Platform/Intel/Tools/GNUmakefile | 30 +++++++++++++++++++++++++++++
Platform/Intel/Tools/Makefile | 33 ++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 Platform/Intel/Tools/GNUmakefile
create mode 100644 Platform/Intel/Tools/Makefile
diff --git a/Platform/Intel/Tools/GNUmakefile b/Platform/Intel/Tools/GNUmakefile
new file mode 100644
index 0000000000..195b72d9af
--- /dev/null
+++ b/Platform/Intel/Tools/GNUmakefile
@@ -0,0 +1,30 @@
+##@file
+# GNUmakefile for building C utilities.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+MAKEROOT = $(EDK_TOOLS_PATH)/Source/C
+
+APPLICATIONS = \
+ BfmLib \
+ FCE \
+ FMMT \
+
+SUBDIRS := $(APPLICATIONS)
+
+$(APPLICATIONS): $(MAKEROOT)/bin
+
+.PHONY: subdirs $(SUBDIRS)
+subdirs: $(SUBDIRS)
+$(SUBDIRS):
+ $(MAKE) -C $@
+
+.PHONY: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+$(patsubst %,%-clean,$(sort $(SUBDIRS))):
+ -$(MAKE) -C $(@:-clean=) clean
+
+clean: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+
diff --git a/Platform/Intel/Tools/Makefile b/Platform/Intel/Tools/Makefile
new file mode 100644
index 0000000000..3472b0e6f0
--- /dev/null
+++ b/Platform/Intel/Tools/Makefile
@@ -0,0 +1,33 @@
+##@file
+# makefile for building C utilities.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPLICATIONS = \
+ BfmLib \
+ FCE\
+ FMMT\
+
+all: $(APPLICATIONS)
+ @echo.
+ @echo ######################
+ @echo # Build executables
+ @echo ######################
+ @if not exist $(BIN_PATH) mkdir $(BIN_PATH)
+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat all $**
+
+.PHONY: clean
+clean: $(APPLICATIONS)
+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat clean $**
+
+.PHONY: cleanall
+cleanall: $(APPLICATIONS)
+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat cleanall $**
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.rule
+
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen
2019-06-21 1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
` (3 preceding siblings ...)
2019-06-21 1:26 ` [edk2-platform patch 4/6] Platform\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
@ 2019-06-21 1:26 ` Zhang, Shenglei
2019-06-26 2:03 ` [edk2-devel] " Liming Gao
2019-06-21 1:26 ` [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
2019-06-21 2:25 ` [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Yao, Jiewen
6 siblings, 1 reply; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21 1:26 UTC (permalink / raw)
To: devel; +Cc: Bob Feng, Liming Gao
The utility of this tool is part of build process for IA32/X64 FD.
It generates FIT table.
https://bugzilla.tianocore.org/show_bug.cgi?id=1849
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++++++++++++++++++
Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
Silicon/Intel/Tools/FitGen/Makefile | 17 +
4 files changed, 3218 insertions(+)
create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
diff --git a/Silicon/Intel/Tools/FitGen/FitGen.c b/Silicon/Intel/Tools/FitGen/FitGen.c
new file mode 100644
index 0000000000..faf9880060
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/FitGen.c
@@ -0,0 +1,3137 @@
+/**@file
+This utility is part of build process for IA32/X64 FD.
+It generates FIT table.
+
+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FitGen.h"
+
+//
+// FIT spec
+//
+#pragma pack (1)
+typedef struct {
+ UINT64 Address;
+ UINT8 Size[3];
+ UINT8 Rsvd;
+ UINT16 Version;
+ UINT8 Type:7;
+ UINT8 C_V:1;
+ UINT8 Checksum;
+} FIRMWARE_INTERFACE_TABLE_ENTRY;
+
+//
+// Struct for policy
+//
+typedef struct {
+ UINT16 IndexPort;
+ UINT16 DataPort;
+ UINT8 Width;
+ UINT8 Bit;
+ UINT16 Index;
+ UINT8 Size[3];
+ UINT8 Rsvd;
+ UINT16 Version; // == 0
+ UINT8 Type:7;
+ UINT8 C_V:1;
+ UINT8 Checksum;
+} FIRMWARE_INTERFACE_TABLE_ENTRY_PORT;
+
+#define FIT_ALIGNMENT 0x3F // 0xF is required previously, but if we need exclude FIT, we must set 64 bytes alignment.
+#define BIOS_MODULE_ALIGNMENT 0x3F // 64 bytes for AnC
+#define MICROCODE_ALIGNMENT 0x7FF
+
+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE 256
+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE 384
+
+#define ACM_HEADER_VERSION_3 (3 << 16)
+#define ACM_MODULE_TYPE_CHIPSET_ACM 2
+#define ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET 0x1
+#define ACM_MODULE_SUBTYPE_ANC_MODULE 0x2
+#define ACM_MODULE_FLAG_PREPRODUCTION 0x4000
+#define ACM_MODULE_FLAG_DEBUG_SIGN 0x8000
+
+
+typedef struct {
+ UINT16 ModuleType;
+ UINT16 ModuleSubType;
+ UINT32 HeaderLen;
+ UINT32 HeaderVersion;
+ UINT16 ChipsetID;
+ UINT16 Flags;
+ UINT32 ModuleVendor;
+ UINT32 Date;
+ UINT32 Size;
+ UINT16 TxtSvn;
+ UINT16 SeSvn;
+ UINT32 CodeControl;
+ UINT32 ErrorEntryPoint;
+ UINT32 GDTLimit;
+ UINT32 GDTBasePtr;
+ UINT32 SegSel;
+ UINT32 EntryPoint;
+ UINT8 Rsvd2[64];
+ UINT32 KeySize; // 64
+ UINT32 ScratchSize; // 2 * KeySize + 15
+//UINT8 RSAPubKey[64 * 4]; // KeySize * 4
+//UINT32 RSAPubExp;
+//UINT8 RSASig[256];
+ // End of AC module header
+//UINT8 Scratch[(64 * 2 + 15) * 4]; // ScratchSize * 4
+ // User Area
+//UINT8 UserArea[1];
+} ACM_FORMAT;
+
+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_3 0x03
+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_4 0x04
+
+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION CHIPSET_ACM_INFORMATION_TABLE_VERSION_3
+
+#define CHIPSET_ACM_INFORMATION_TABLE_GUID_V03 \
+ { 0x7FC03AAA, 0x18DB46A7, 0x8F69AC2E, 0x5A7F418D }
+
+#define CHIPSET_ACM_TYPE_BIOS 0
+#define CHIPSET_ACM_TYPE_SINIT 1
+
+typedef struct {
+ UINT32 Guid0;
+ UINT32 Guid1;
+ UINT32 Guid2;
+ UINT32 Guid3;
+} ACM_GUID;
+
+typedef struct {
+ ACM_GUID Guid;
+ UINT8 ChipsetACMType;
+ UINT8 Version;
+ UINT16 Length;
+ UINT32 ChipsetIDList;
+ UINT32 OsSinitTableVer;
+ UINT32 MinMleHeaderVer;
+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3)
+ UINT32 Capabilities;
+ UINT8 AcmVersion;
+ UINT8 AcmRevision[3];
+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4)
+ UINT32 ProcessorIDList;
+//#endif
+//#endif
+} CHIPSET_ACM_INFORMATION_TABLE;
+
+#define ACM_CHIPSET_ID_REVISION_ID_MAKE 0x1
+
+typedef struct {
+ UINT32 Flags;
+ UINT16 VendorID;
+ UINT16 DeviceID;
+ UINT16 RevisionID;
+ UINT8 Reserved[6];
+} ACM_CHIPSET_ID;
+
+typedef struct {
+ UINT32 Count;
+ ACM_CHIPSET_ID ChipsetID[1];
+} CHIPSET_ID_LIST;
+
+typedef struct {
+ UINT32 FMS;
+ UINT32 FMSMask;
+ UINT64 PlatformID;
+ UINT64 PlatformMask;
+} ACM_PROCESSOR_ID;
+
+typedef struct {
+ UINT32 Count;
+ ACM_PROCESSOR_ID ProcessorID[1];
+} PROCESSOR_ID_LIST;
+
+#pragma pack ()
+
+
+ACM_GUID mChipsetAcmInformationTableGuid03 = CHIPSET_ACM_INFORMATION_TABLE_GUID_V03;
+
+
+//
+// BIOS INFO data structure
+// This is self contained data structure for BIOS info
+//
+#pragma pack (1)
+#define BIOS_INFO_SIGNATURE SIGNATURE_64 ('$', 'B', 'I', 'O', 'S', 'I', 'F', '$')
+typedef struct {
+ UINT64 Signature;
+ UINT32 EntryCount;
+ UINT32 Reserved;
+//BIOS_INFO_STRUCT Struct[EntryCount];
+} BIOS_INFO_HEADER;
+
+//
+// BIOS_INFO_STRUCT attributes
+// bits[0:3] means general attributes
+// bits[4:7] means type specific attributes
+//
+#define BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT 0x01
+#define BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION 0x10
+#define BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB 0x10
+
+typedef struct {
+ //
+ // FitTable entry type
+ //
+ UINT8 Type;
+ //
+ // BIOS_INFO_STRUCT attributes
+ //
+ UINT8 Attributes;
+ //
+ // FitTable entry version
+ //
+ UINT16 Version;
+ //
+ // FitTable entry real size
+ //
+ UINT32 Size;
+ //
+ // FitTable entry address
+ //
+ UINT64 Address;
+} BIOS_INFO_STRUCT;
+
+#pragma pack ()
+
+#define MAX_BIOS_MODULE_ENTRY 0x20
+#define MAX_MICROCODE_ENTRY 0x20
+#define MAX_OPTIONAL_ENTRY 0x20
+#define MAX_PORT_ENTRY 0x20
+
+#define DEFAULT_FIT_TABLE_POINTER_OFFSET 0x40
+#define DEFAULT_FIT_ENTRY_VERSION 0x0100
+
+#define MEMORY_TO_FLASH(FileBuffer, FvBuffer, FvSize) \
+ (UINTN)(0x100000000 - ((UINTN)(FvBuffer) + (UINTN)(FvSize) - (UINTN)(FileBuffer)))
+#define FLASH_TO_MEMORY(Address, FvBuffer, FvSize) \
+ (VOID *)(UINTN)((UINTN)(FvBuffer) + (UINTN)(FvSize) - (0x100000000 - (UINTN)(Address)))
+
+#define FIT_TABLE_TYPE_HEADER 0
+#define FIT_TABLE_TYPE_MICROCODE 1
+#define FIT_TABLE_TYPE_STARTUP_ACM 2
+#define FIT_TABLE_TYPE_BIOS_MODULE 7
+#define FIT_TABLE_TYPE_TPM_POLICY 8
+#define FIT_TABLE_TYPE_BIOS_POLICY 9
+#define FIT_TABLE_TYPE_TXT_POLICY 10
+#define FIT_TABLE_TYPE_KEY_MANIFEST 11
+#define FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST 12
+#define FIT_TABLE_TYPE_BIOS_DATA_AREA 13
+#define FIT_TABLE_TYPE_CSE_SECURE_BOOT 16
+
+typedef struct {
+ UINT32 Type;
+ UINT32 Address;
+ UINT32 Size;
+ UINT32 Version; // Used by OptionalModule and PortModule only
+} FIT_TABLE_CONTEXT_ENTRY;
+
+typedef struct {
+ BOOLEAN Clear;
+ UINT32 FitTablePointerOffset;
+ UINT32 FitTablePointerOffset2;
+ UINT32 FitEntryNumber;
+ UINT32 BiosModuleNumber;
+ UINT32 MicrocodeNumber;
+ UINT32 OptionalModuleNumber;
+ UINT32 PortModuleNumber;
+ UINT32 GlobalVersion;
+ UINT32 FitHeaderVersion;
+ FIT_TABLE_CONTEXT_ENTRY StartupAcm;
+ UINT32 StartupAcmVersion;
+ FIT_TABLE_CONTEXT_ENTRY BiosModule[MAX_BIOS_MODULE_ENTRY];
+ UINT32 BiosModuleVersion;
+ FIT_TABLE_CONTEXT_ENTRY Microcode[MAX_MICROCODE_ENTRY];
+ BOOLEAN MicrocodeAlignment;
+ UINT32 MicrocodeVersion;
+ FIT_TABLE_CONTEXT_ENTRY OptionalModule[MAX_OPTIONAL_ENTRY];
+ FIT_TABLE_CONTEXT_ENTRY PortModule[MAX_PORT_ENTRY];
+} FIT_TABLE_CONTEXT;
+
+FIT_TABLE_CONTEXT gFitTableContext = {0};
+
+unsigned int
+xtoi (
+ char *str
+ );
+
+VOID
+PrintUtilityInfo (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Displays the standard utility information to STDOUT
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ printf (
+ "%s - Tiano IA32/X64 FIT table generation Utility."" Version %i.%i\n\n",
+ UTILITY_NAME,
+ UTILITY_MAJOR_VERSION,
+ UTILITY_MINOR_VERSION
+ );
+}
+
+VOID
+PrintUsage (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Displays the utility usage syntax to STDOUT
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ printf ("Usage (generate): %s [-D] InputFvRecoveryFile OutputFvRecoveryFile\n"
+ "\t[-V <FitEntryDefaultVersion>]\n"
+ "\t[-F <FitTablePointerOffset>] [-F <FitTablePointerOffset>] [-V <FitHeaderVersion>]\n"
+ "\t[-NA]\n"
+ "\t[-CLEAR]\n"
+ "\t[-I <BiosInfoGuid>]\n"
+ "\t[-S <StartupAcmAddress StartupAcmSize>|<StartupAcmGuid>] [-V <StartupAcmVersion>]\n"
+ "\t[-B <BiosModuleAddress BiosModuleSize>] [-B ...] [-V <BiosModuleVersion>]\n"
+ "\t[-M <MicrocodeAddress MicrocodeSize>] [-M ...]|[-U <MicrocodeFv MicrocodeBase>|<MicrocodeRegionOffset MicrocodeRegionSize>|<MicrocodeGuid>] [-V <MicrocodeVersion>]\n"
+ "\t[-O RecordType <RecordDataAddress RecordDataSize>|<RESERVE RecordDataSize>|<RecordDataGuid>|<RecordBinFile> [-V <RecordVersion>]] [-O ... [-V ...]]\n"
+ "\t[-P RecordType <IndexPort DataPort Width Bit Index> [-V <RecordVersion>]] [-P ... [-V ...]]\n"
+ , UTILITY_NAME);
+ printf (" Where:\n");
+ printf ("\t-D - It is FD file instead of FV file. (The tool will search FV file)\n");
+ printf ("\tInputFvRecoveryFile - Name of the input FvRecovery.fv file.\n");
+ printf ("\tOutputFvRecoveryFile - Name of the output FvRecovery.fv file.\n");
+ printf ("\tFitTablePointerOffset - FIT table pointer offset. 0x%x as default. 0x18 for current soon to be obsoleted CPUs. User can set both.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
+ printf ("\tBiosInfoGuid - Guid of BiosInfo Module. If this module exists, StartupAcm/Bios/Microcode can be optional.\n");
+ printf ("\tStartupAcmAddress - Address of StartupAcm.\n");
+ printf ("\tStartupAcmSize - Size of StartupAcm.\n");
+ printf ("\tStartupAcmGuid - Guid of StartupAcm Module, if StartupAcm is in a BiosModule, it will be excluded form that.\n");
+ printf ("\tBiosModuleAddress - Address of BiosModule. User should ensure there is no overlap.\n");
+ printf ("\tBiosModuleSize - Size of BiosModule.\n");
+ printf ("\tMicrocodeAddress - Address of Microcode.\n");
+ printf ("\tMicrocodeSize - Size of Microcode.\n");
+ printf ("\tMicrocodeFv - Name of Microcode.fv file.\n");
+ printf ("\tMicrocodeBase - The base address of Microcode.fv in final FD image.\n");
+ printf ("\tMicrocodeRegionOffset - Offset of Microcode region in input FD image.\n");
+ printf ("\tMicrocodeRegionSize - Size of Microcode region in input FD image.\n");
+ printf ("\tMicrocodeGuid - Guid of Microcode Module.\n");
+ printf ("\t-NA - No 0x800 aligned Microcode requirement. No -NA means Microcode is 0x800 aligned.\n");
+ printf ("\tRecordType - FIT entry record type. User should ensure it is ordered.\n");
+ printf ("\tRecordDataAddress - FIT entry record data address.\n");
+ printf ("\tRecordDataSize - FIT entry record data size.\n");
+ printf ("\tRecordDataGuid - FIT entry record data GUID.\n");
+ printf ("\tRecordBinFile - FIT entry record data binary file.\n");
+ printf ("\tFitEntryDefaultVersion - The default version for all FIT table entries. 0x%04x is used if this is not specified.\n", DEFAULT_FIT_ENTRY_VERSION);
+ printf ("\tFitHeaderVersion - The version for FIT header. (Override default version)\n");
+ printf ("\tStartupAcmVersion - The version for StartupAcm. (Override default version)\n");
+ printf ("\tBiosModuleVersion - The version for BiosModule. (Override default version)\n");
+ printf ("\tMicrocodeVersion - The version for Microcode. (Override default version)\n");
+ printf ("\tRecordVersion - The version for Record. (Override default version)\n");
+ printf ("\tIndexPort - The Index Port Number.\n");
+ printf ("\tDataPort - The Data Port Number.\n");
+ printf ("\tWidth - The Width of the port.\n");
+ printf ("\tBit - The Bit Number of the port.\n");
+ printf ("\tIndex - The Index Number of the port.\n");
+ printf ("\nUsage (view): %s [-view] InputFile -F <FitTablePointerOffset>\n", UTILITY_NAME);
+ printf (" Where:\n");
+ printf ("\tInputFile - Name of the input file.\n");
+ printf ("\tFitTablePointerOffset - FIT table pointer offset from end of file. 0x%x as default.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
+ printf ("\nTool return values:\n");
+ printf ("\tSTATUS_SUCCESS=%d, STATUS_WARNING=%d, STATUS_ERROR=%d\n", STATUS_SUCCESS, STATUS_WARNING, STATUS_ERROR);
+}
+
+VOID *
+SetMem (
+ OUT VOID *Buffer,
+ IN UINTN Length,
+ IN UINT8 Value
+ )
+{
+ //
+ // Declare the local variables that actually move the data elements as
+ // volatile to prevent the optimizer from replacing this function with
+ // the intrinsic memset()
+ //
+ volatile UINT8 *Pointer;
+
+ Pointer = (UINT8*)Buffer;
+ while (Length-- > 0) {
+ *(Pointer++) = Value;
+ }
+ return Buffer;
+}
+
+STATUS
+ReadInputFile (
+ IN CHAR8 *FileName,
+ OUT UINT8 **FileData,
+ OUT UINT32 *FileSize,
+ OUT UINT8 **FileBufferRaw OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Read input file
+
+Arguments:
+
+ FileName - The input file name
+ FileData - The input file data, the memory is aligned.
+ FileSize - The input file size
+ FileBufferRaw - The memory to hold input file data. The caller must free the memory.
+
+Returns:
+
+ STATUS_SUCCESS - The file found and data read
+ STATUS_ERROR - The file data is not read
+ STATUS_WARNING - The file is not found
+
+--*/
+{
+ FILE *FpIn;
+ UINT32 TempResult;
+
+ //
+ // Open the Input FvRecovery.fv file
+ //
+ if ((FpIn = fopen (FileName, "rb")) == NULL) {
+ //
+ // Return WARNING, let caller make decision
+ //
+// Error (NULL, 0, 0, "Unable to open file", FileName);
+ return STATUS_WARNING;
+ }
+ //
+ // Get the Input FvRecovery.fv file size
+ //
+ fseek (FpIn, 0, SEEK_END);
+ *FileSize = ftell (FpIn);
+ //
+ // Read the contents of input file to memory buffer
+ //
+ if (FileBufferRaw != NULL) {
+ *FileBufferRaw = (UINT8 *) malloc (*FileSize + 0x10000);
+ if (NULL == *FileBufferRaw) {
+ Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
+ fclose (FpIn);
+ return STATUS_ERROR;
+ }
+ TempResult = 0x10000 - (UINT32) ((UINTN)*FileBufferRaw & 0x0FFFF);
+ *FileData = (UINT8 *)((UINTN)*FileBufferRaw + TempResult);
+ } else {
+ *FileData = (UINT8 *) malloc (*FileSize);
+ if (NULL == *FileData) {
+ Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
+ fclose (FpIn);
+ return STATUS_ERROR;
+ }
+ }
+ fseek (FpIn, 0, SEEK_SET);
+ TempResult = fread (*FileData, 1, *FileSize, FpIn);
+ if (TempResult != *FileSize) {
+ Error (NULL, 0, 0, "Read input file error!", NULL);
+ if (FileBufferRaw != NULL) {
+ free ((VOID *)*FileBufferRaw);
+ } else {
+ free ((VOID *)*FileData);
+ }
+ fclose (FpIn);
+ return STATUS_ERROR;
+ }
+
+ //
+ // Close the input FvRecovery.fv file
+ //
+ fclose (FpIn);
+
+ return STATUS_SUCCESS;
+}
+
+UINT8 *
+FindNextFvHeader (
+ IN UINT8 *FileBuffer,
+ IN UINTN FileLength
+ )
+/*++
+
+ Routine Description:
+ Find next FvHeader in the FileBuffer
+
+ Parameters:
+ FileBuffer - The start FileBuffer which needs to be searched
+ FileLength - The whole File Length.
+ Return:
+ FvHeader - The FvHeader is found successfully.
+ NULL - The FvHeader is not found.
+
+--*/
+{
+ UINT8 *FileHeader;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ UINT16 FileChecksum;
+
+ FileHeader = FileBuffer;
+ for (; (UINTN)FileBuffer < (UINTN)FileHeader + FileLength; FileBuffer += 8) {
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer;
+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+ //
+ // potential candidate
+ //
+
+ //
+ // Check checksum
+ //
+ if (FvHeader->FvLength > FileLength) {
+ continue;
+ }
+ if (FvHeader->HeaderLength >= FileLength) {
+ continue;
+ }
+ FileChecksum = CalculateChecksum16 ((UINT16 *)FileBuffer, FvHeader->HeaderLength / sizeof (UINT16));
+ if (FileChecksum != 0) {
+ continue;
+ }
+
+ //
+ // Check revision and reserved field
+ //
+#if (PI_SPECIFICATION_VERSION < 0x00010000)
+ if ((FvHeader->Revision == EFI_FVH_REVISION) &&
+ (FvHeader->Reserved[0] == 0) &&
+ (FvHeader->Reserved[1] == 0) &&
+ (FvHeader->Reserved[2] == 0) ){
+ return FileBuffer;
+ }
+#else
+ if ((FvHeader->Revision == EFI_FVH_PI_REVISION) &&
+ (FvHeader->Reserved[0] == 0) ){
+ return FileBuffer;
+ }
+#endif
+ }
+ }
+
+ return NULL;
+}
+
+UINT8 *
+FindFileFromFvByGuid (
+ IN UINT8 *FvBuffer,
+ IN UINT32 FvSize,
+ IN EFI_GUID *Guid,
+ OUT UINT32 *FileSize
+ )
+/*++
+
+Routine Description:
+
+ Find File with GUID in an FV
+
+Arguments:
+
+ FvBuffer - FV binary buffer
+ FvSize - FV size
+ Guid - File GUID value to be searched
+ FileSize - Guid File size
+
+Returns:
+
+ FileLocation - Guid File location.
+ NULL - Guid File is not found.
+
+--*/
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ UINT64 FvLength;
+ EFI_GUID *TempGuid;
+ UINT8 *FixPoint;
+ UINT32 Offset;
+ UINT32 FileLength;
+ UINT32 FileOccupiedSize;
+
+ //
+ // Find the FFS file
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader (FvBuffer, FvSize);
+ if (NULL == FvHeader) {
+ return NULL;
+ }
+ while (TRUE) {
+ FvLength = FvHeader->FvLength;
+
+ //
+ // Prepare to walk the FV image
+ //
+ InitializeFvLib (FvHeader, (UINT32)FvLength);
+
+ FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
+ Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
+
+ while (Offset < FvLength) {
+ TempGuid = (EFI_GUID *)&(FileHeader->Name);
+ FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
+ FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
+ if ((CompareGuid (TempGuid, Guid)) == 0) {
+ //
+ // Good! Find it.
+ //
+ FixPoint = ((UINT8 *)FileHeader + sizeof(EFI_FFS_FILE_HEADER));
+ //
+ // Find the position of file module, the offset
+ // between the position and the end of FvRecovery.fv file
+ // should not exceed 128kB to prevent reset vector from
+ // outside legacy E and F segment
+ //
+ if ((UINTN)FvHeader + FvLength - (UINTN)FixPoint > 0x20000) {
+ // printf ("WARNING: The position of file module is not in E and F segment!\n");
+ // return NULL;
+ }
+ *FileSize = FileLength - sizeof(EFI_FFS_FILE_HEADER);
+ #if (PI_SPECIFICATION_VERSION < 0x00010000)
+ if (FileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
+ *FileSize -= sizeof(EFI_FFS_FILE_TAIL);
+ }
+ #endif
+ return FixPoint;
+ }
+ FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize);
+ Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
+ }
+
+ //
+ // Not found, check next FV
+ //
+ if ((UINTN)FvBuffer + FvSize > (UINTN)FvHeader + FvLength) {
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader ((UINT8 *)FvHeader + (UINTN)FvLength, (UINTN)FvBuffer + FvSize - ((UINTN)FvHeader + (UINTN)FvLength));
+ if (FvHeader == NULL) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Not found
+ //
+ return NULL;
+}
+
+BOOLEAN
+IsGuidData (
+ IN CHAR8 *StringData,
+ OUT EFI_GUID *Guid
+ )
+/*++
+
+Routine Description:
+
+ Check whether a string is a GUID
+
+Arguments:
+
+ StringData - the String
+ Guid - Guid to hold the value
+
+Returns:
+
+ TRUE - StringData is a GUID, and Guid field is filled.
+ FALSE - StringData is not a GUID
+
+--*/
+{
+ if (strlen (StringData) != strlen ("00000000-0000-0000-0000-000000000000")) {
+ return FALSE;
+ }
+ if ((StringData[8] != '-') ||
+ (StringData[13] != '-') ||
+ (StringData[18] != '-') ||
+ (StringData[23] != '-') ) {
+ return FALSE;
+ }
+
+ StringToGuid (StringData, Guid);
+
+ return TRUE;
+}
+
+VOID
+CheckOverlap (
+ IN UINT32 Address,
+ IN UINT32 Size
+ )
+{
+ INTN Index;
+
+ for (Index = 0; Index < (INTN)gFitTableContext.BiosModuleNumber; Index ++) {
+ if ((gFitTableContext.BiosModule[Index].Address <= Address) &&
+ ((gFitTableContext.BiosModule[Index].Size - Size) >= (Address - gFitTableContext.BiosModule[Index].Address))) {
+ UINT32 TempSize;
+ INT32 SubIndex;
+
+ //
+ // Found overlap, split BiosModuleEntry
+ // Currently only support StartupAcm in 1 BiosModule. It does not support StartupAcm across 2 BiosModule or more.
+ //
+ if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
+ Error (NULL, 0, 0, "Too many Bios Module!", NULL);
+ return ;
+ }
+
+ if (Address != gFitTableContext.BiosModule[Index].Address) {
+ //
+ // Skip the entry whose start address is same as StartupAcm
+ //
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = gFitTableContext.BiosModule[Index].Address;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = Address - gFitTableContext.BiosModule[Index].Address;
+ gFitTableContext.BiosModuleNumber ++;
+ gFitTableContext.FitEntryNumber++;
+ }
+
+ TempSize = gFitTableContext.BiosModule[Index].Address + gFitTableContext.BiosModule[Index].Size;
+ gFitTableContext.BiosModule[Index].Address = Address + Size;
+ gFitTableContext.BiosModule[Index].Size = TempSize - gFitTableContext.BiosModule[Index].Address;
+
+ if (gFitTableContext.BiosModule[Index].Size == 0) {
+ //
+ // remove the entry if size is 0
+ //
+ for (SubIndex = Index; SubIndex < (INTN)gFitTableContext.BiosModuleNumber - 1; SubIndex ++) {
+ gFitTableContext.BiosModule[SubIndex].Address = gFitTableContext.BiosModule[SubIndex + 1].Address;
+ gFitTableContext.BiosModule[SubIndex].Size = gFitTableContext.BiosModule[SubIndex + 1].Size;
+ }
+ gFitTableContext.BiosModuleNumber --;
+ gFitTableContext.FitEntryNumber--;
+ }
+ break;
+ }
+ }
+}
+
+UINT32
+GetFitEntryNumber (
+ IN INTN argc,
+ IN CHAR8 **argv,
+ IN UINT8 *FdBuffer,
+ IN UINT32 FdSize
+ )
+/*++
+
+Routine Description:
+
+ Get FIT entry number and fill global FIT table context, from argument
+
+Arguments:
+
+ argc - Number of command line parameters.
+ argv - Array of pointers to parameter strings.
+ FdBuffer - FD binary buffer
+ FdSize - FD size
+
+Returns:
+
+ FitEntryNumber - The FIT entry number
+ 0 - Argument parse fail
+
+*/
+{
+ EFI_GUID Guid;
+ INTN Index;
+ UINT8 *FileBuffer;
+ UINT32 FileSize;
+ UINT32 Type;
+ UINT8 *MicrocodeFileBuffer;
+ UINT8 *MicrocodeFileBufferRaw;
+ UINT32 MicrocodeFileSize;
+ UINT32 MicrocodeBase;
+ UINT32 MicrocodeSize;
+ UINT8 *MicrocodeBuffer;
+ UINT32 MicrocodeRegionOffset;
+ UINT32 MicrocodeRegionSize;
+ STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ UINTN FitEntryNumber;
+ BOOLEAN BiosInfoExist;
+ BIOS_INFO_HEADER *BiosInfo;
+ BIOS_INFO_STRUCT *BiosInfoStruct;
+ UINTN BiosInfoIndex;
+
+ //
+ // Init index
+ //
+ Index = 3;
+ if (((strcmp (argv[1], "-D") == 0) ||
+ (strcmp (argv[1], "-d") == 0)) ) {
+ Index ++;
+ }
+
+ //
+ // Fill Global Version
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-V") != 0) &&
+ (strcmp (argv[Index], "-v") != 0)) ) {
+ gFitTableContext.GlobalVersion = DEFAULT_FIT_ENTRY_VERSION;
+ } else {
+ gFitTableContext.GlobalVersion = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+
+ //
+ // 0. FIT Header
+ //
+ gFitTableContext.FitEntryNumber = 1;
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-F") != 0) &&
+ (strcmp (argv[Index], "-f") != 0)) ) {
+ //
+ // Use default address
+ //
+ gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.FitTablePointerOffset = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+
+ //
+ // 0.1 FIT Header 2
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-F") != 0) &&
+ (strcmp (argv[Index], "-f") != 0)) ) {
+ //
+ // Bypass
+ //
+ gFitTableContext.FitTablePointerOffset2 = 0;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.FitTablePointerOffset2 = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+
+ //
+ // 0.2 FIT Header version
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-V") != 0) &&
+ (strcmp (argv[Index], "-v") != 0)) ) {
+ //
+ // Bypass
+ //
+ gFitTableContext.FitHeaderVersion = gFitTableContext.GlobalVersion;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.FitHeaderVersion = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+
+ //
+ // 0.3 Microcode alignment
+ //
+ if ((Index >= argc) ||
+ ((strcmp (argv[Index], "-NA") != 0) &&
+ (strcmp (argv[Index], "-na") != 0)) ) {
+ //
+ // by pass
+ //
+ gFitTableContext.MicrocodeAlignment = TRUE;
+ } else {
+ //
+ // no alignment
+ //
+ gFitTableContext.MicrocodeAlignment = FALSE;
+ Index += 1;
+ }
+
+ //
+ // 0.4 Clear FIT table related memory
+ //
+ if ((Index >= argc) ||
+ ((strcmp (argv[Index], "-CLEAR") != 0) &&
+ (strcmp (argv[Index], "-clear") != 0)) ) {
+ //
+ // by pass
+ //
+ gFitTableContext.Clear = FALSE;
+ } else {
+ //
+ // Clear FIT table
+ //
+ gFitTableContext.Clear = TRUE;
+ //
+ // Do not parse any more
+ //
+ return 0;
+ }
+
+ //
+ // 0.5 BiosInfo
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-I") != 0) &&
+ (strcmp (argv[Index], "-i") != 0)) ) {
+ //
+ // Bypass
+ //
+ BiosInfoExist = FALSE;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ BiosInfoExist = TRUE;
+ if (IsGuidData (argv[Index + 1], &Guid)) {
+ FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
+ if (FileBuffer == NULL) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
+ // not found
+ return 0;
+ }
+ BiosInfo = (BIOS_INFO_HEADER *)FileBuffer;
+ for (BiosInfoIndex = 0; BiosInfoIndex < FileSize; BiosInfoIndex++) {
+ if (((BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex))->Signature == BIOS_INFO_SIGNATURE) {
+ BiosInfo = (BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex);
+ }
+ }
+ if (BiosInfo->Signature != BIOS_INFO_SIGNATURE) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, Signature Error!", NULL);
+ // not found
+ return 0;
+ }
+ BiosInfoStruct = (BIOS_INFO_STRUCT *)(BiosInfo + 1);
+
+ for (BiosInfoIndex = 0; BiosInfoIndex < BiosInfo->EntryCount; BiosInfoIndex++) {
+ if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT) != 0) {
+ continue;
+ }
+ switch (BiosInfoStruct[BiosInfoIndex].Type) {
+ case FIT_TABLE_TYPE_HEADER:
+ Error (NULL, 0, 0, "-I Parameter incorrect, Header Type unsupported!", NULL);
+ return 0;
+ case FIT_TABLE_TYPE_STARTUP_ACM:
+ if (gFitTableContext.StartupAcm.Type != 0) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, Duplicated StartupAcm!", NULL);
+ return 0;
+ }
+ gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM;
+ gFitTableContext.StartupAcm.Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+ gFitTableContext.StartupAcm.Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+ gFitTableContext.StartupAcmVersion = BiosInfoStruct[BiosInfoIndex].Version;
+ gFitTableContext.FitEntryNumber ++;
+ break;
+ case FIT_TABLE_TYPE_BIOS_MODULE:
+ if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB) != 0) {
+ continue;
+ }
+ if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Bios Module!", NULL);
+ return 0;
+ }
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+ gFitTableContext.BiosModuleVersion = BiosInfoStruct[BiosInfoIndex].Version;
+ gFitTableContext.BiosModuleNumber ++;
+ gFitTableContext.FitEntryNumber ++;
+ break;
+ case FIT_TABLE_TYPE_MICROCODE:
+ if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION) == 0) {
+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Microcode!", NULL);
+ return 0;
+ }
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+ gFitTableContext.MicrocodeVersion = BiosInfoStruct[BiosInfoIndex].Version;
+ gFitTableContext.MicrocodeNumber++;
+ gFitTableContext.FitEntryNumber++;
+ } else {
+ MicrocodeRegionOffset = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+ MicrocodeRegionSize = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+ if (MicrocodeRegionOffset == 0) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionOffset is 0", NULL);
+ return 0;
+ }
+ if (MicrocodeRegionSize == 0) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize is 0", NULL);
+ return 0;
+ }
+ if (MicrocodeRegionSize > FdSize) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize too large", NULL);
+ return 0;
+ }
+
+ MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize);
+ MicrocodeFileSize = MicrocodeRegionSize;
+ MicrocodeBase = MicrocodeRegionOffset;
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+ // Skip FV header + FFS header
+ MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
+ } else {
+ MicrocodeBuffer = MicrocodeFileBuffer;
+ }
+ while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) {
+ if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
+ break;
+ }
+ if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
+ break;
+ }
+ if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
+ MicrocodeSize = 2048;
+ } else {
+ //
+ // MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment.
+ //
+ if (gFitTableContext.MicrocodeAlignment) {
+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) + MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
+ } else {
+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
+ }
+ }
+
+ //
+ // Add Microcode
+ //
+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+ printf ("-I Parameter incorrect, Too many Microcode!\n");
+ return 0;
+ }
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer);
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
+ gFitTableContext.MicrocodeNumber++;
+ gFitTableContext.FitEntryNumber++;
+
+ MicrocodeBuffer += MicrocodeSize;
+ }
+ }
+ break;
+ case FIT_TABLE_TYPE_TPM_POLICY:
+ case FIT_TABLE_TYPE_BIOS_POLICY:
+ case FIT_TABLE_TYPE_TXT_POLICY:
+ case FIT_TABLE_TYPE_KEY_MANIFEST:
+ case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
+ case FIT_TABLE_TYPE_BIOS_DATA_AREA:
+ case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
+ default :
+ if (BiosInfoStruct[BiosInfoIndex].Version != 0) {
+ if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Optional Module!", NULL);
+ return 0;
+ }
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = BiosInfoStruct[BiosInfoIndex].Type;
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version;
+ gFitTableContext.OptionalModuleNumber++;
+ gFitTableContext.FitEntryNumber++;
+ } else {
+ if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Port Module!", NULL);
+ return 0;
+ }
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = BiosInfoStruct[BiosInfoIndex].Type;
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT32)(BiosInfoStruct[BiosInfoIndex].Address >> 32);
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version;
+ gFitTableContext.PortModuleNumber++;
+ gFitTableContext.FitEntryNumber++;
+ }
+ break;
+ }
+ }
+
+ } else {
+ Error (NULL, 0, 0, "-I Parameter incorrect, expect GUID!", NULL);
+ return 0;
+ }
+ Index += 2;
+ }
+
+ //
+ // 1. StartupAcm
+ //
+ do {
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-S") != 0) &&
+ (strcmp (argv[Index], "-s") != 0)) ) {
+ if (BiosInfoExist && (gFitTableContext.StartupAcm.Type == FIT_TABLE_TYPE_STARTUP_ACM)) {
+ break;
+ }
+// Error (NULL, 0, 0, "-S Parameter incorrect, expect -S!", NULL);
+// return 0;
+ printf ("-S not found. WARNING!\n");
+ break;
+ }
+ if (IsGuidData (argv[Index + 1], &Guid)) {
+ FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
+ if (FileBuffer == NULL) {
+ Error (NULL, 0, 0, "-S Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
+ // not found
+ return 0;
+ }
+ FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
+ Index += 2;
+ } else {
+ if (Index + 2 >= argc) {
+ Error (NULL, 0, 0, "-S Parameter incorrect, expect Address Size!", NULL);
+ return 0;
+ }
+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+ FileSize = xtoi (argv[Index + 2]);
+ Index += 3;
+ }
+ if (gFitTableContext.StartupAcm.Type != 0) {
+ Error (NULL, 0, 0, "-S Parameter incorrect, Duplicated StartupAcm!", NULL);
+ return 0;
+ }
+ gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM;
+ gFitTableContext.StartupAcm.Address = (UINT32) (UINTN) FileBuffer;
+ gFitTableContext.StartupAcm.Size = FileSize;
+ gFitTableContext.FitEntryNumber ++;
+
+ //
+ // 1.1 StartupAcm version
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-V") != 0) &&
+ (strcmp (argv[Index], "-v") != 0)) ) {
+ //
+ // Bypass
+ //
+ gFitTableContext.StartupAcmVersion = gFitTableContext.GlobalVersion;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.StartupAcmVersion = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+ } while (FALSE);
+
+ //
+ // 2. BiosModule
+ //
+ do {
+ if ((Index + 2 >= argc) ||
+ ((strcmp (argv[Index], "-B") != 0) &&
+ (strcmp (argv[Index], "-b") != 0)) ) {
+ if (BiosInfoExist && (gFitTableContext.BiosModuleNumber != 0)) {
+ break;
+ }
+// Error (NULL, 0, 0, "-B Parameter incorrect, expect -B!", NULL);
+// return 0;
+ printf ("-B not found. WARNING!\n");
+ break;
+ }
+
+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+ FileSize = xtoi (argv[Index + 2]);
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize;
+ gFitTableContext.BiosModuleNumber ++;
+ gFitTableContext.FitEntryNumber ++;
+
+ while (TRUE) {
+ Index += 3;
+ if (Index + 2 >= argc) {
+ break;
+ }
+ if ((strcmp (argv[Index], "-B") != 0) &&
+ (strcmp (argv[Index], "-b") != 0) ) {
+ break;
+ }
+ if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
+ Error (NULL, 0, 0, "-B Parameter incorrect, Too many Bios Module!", NULL);
+ return 0;
+ }
+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+ FileSize = xtoi (argv[Index + 2]);
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize;
+ gFitTableContext.BiosModuleNumber ++;
+ gFitTableContext.FitEntryNumber++;
+ }
+
+ //
+ // 2.1 BiosModule version
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-V") != 0) &&
+ (strcmp (argv[Index], "-v") != 0)) ) {
+ //
+ // Bypass
+ //
+ gFitTableContext.BiosModuleVersion = gFitTableContext.GlobalVersion;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.BiosModuleVersion = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+ } while (FALSE);
+
+ //
+ // 3. Microcode
+ //
+ while (TRUE) {
+ if (Index + 1 >= argc) {
+ break;
+ }
+ if ((strcmp (argv[Index], "-M") != 0) &&
+ (strcmp (argv[Index], "-m") != 0) ) {
+ break;
+ }
+ if (IsGuidData (argv[Index + 2], &Guid)) {
+ Error (NULL, 0, 0, "-M Parameter incorrect, GUID unsupported!", NULL);
+ return 0;
+ } else {
+ if (Index + 2 >= argc) {
+ break;
+ }
+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+ FileSize = xtoi (argv[Index + 2]);
+ Index += 3;
+ }
+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+ Error (NULL, 0, 0, "-M Parameter incorrect, Too many Microcode!", NULL);
+ return 0;
+ }
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32) (UINTN) FileBuffer;
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = FileSize;
+ gFitTableContext.MicrocodeNumber++;
+ gFitTableContext.FitEntryNumber++;
+ }
+
+ //
+ // 3.1 MicrocodeFv
+ //
+ while (TRUE) {
+ if (Index + 1 >= argc) {
+ break;
+ }
+ if ((strcmp (argv[Index], "-U") != 0) &&
+ (strcmp (argv[Index], "-u") != 0) ) {
+ break;
+ }
+ //
+ // Get Fv
+ //
+ if (IsGuidData (argv[Index + 1], &Guid)) {
+ MicrocodeFileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &MicrocodeFileSize);
+ if (MicrocodeFileBuffer == NULL) {
+ Error (NULL, 0, 0, "-U Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
+ // not found
+ return 0;
+ }
+ Index += 2;
+
+ MicrocodeBuffer = MicrocodeFileBuffer;
+ MicrocodeFileBufferRaw = NULL;
+ MicrocodeRegionOffset = MEMORY_TO_FLASH (MicrocodeFileBuffer, FdBuffer, FdSize);
+ MicrocodeRegionSize = 0;
+ MicrocodeBase = MicrocodeRegionOffset;
+
+ } else {
+ if (Index + 2 >= argc) {
+ break;
+ }
+ Status = ReadInputFile (argv[Index + 1], &MicrocodeFileBuffer, &MicrocodeFileSize, &MicrocodeFileBufferRaw);
+ if (Status != STATUS_SUCCESS) {
+ MicrocodeRegionOffset = xtoi (argv[Index + 1]);
+ MicrocodeRegionSize = xtoi (argv[Index + 2]);
+
+ if (MicrocodeRegionOffset == 0) {
+ Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionOffset is 0, or unable to open file", "%s", argv[Index + 1]);
+ return 0;
+ }
+ if (MicrocodeRegionSize == 0) {
+ Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize is 0", NULL);
+ return 0;
+ }
+ if (MicrocodeRegionSize > FdSize) {
+ Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize too large", NULL);
+ return 0;
+ }
+
+ Index += 3;
+
+ MicrocodeFileBufferRaw = NULL;
+ MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize);
+ MicrocodeFileSize = MicrocodeRegionSize;
+ MicrocodeBase = MicrocodeRegionOffset;
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+ // Skip FV header + FFS header
+ MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
+ } else {
+ MicrocodeBuffer = MicrocodeFileBuffer;
+ }
+ } else {
+ MicrocodeBase = xtoi (argv[Index + 2]);
+ Index += 3;
+ MicrocodeRegionOffset = 0;
+ MicrocodeRegionSize = 0;
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+ // Skip FV header + FFS header
+ MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
+ } else {
+ MicrocodeBuffer = MicrocodeFileBuffer;
+ }
+ }
+ }
+ while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) {
+ if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
+ break;
+ }
+ if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
+ break;
+ }
+ if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
+ MicrocodeSize = 2048;
+ } else {
+ //
+ // MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment.
+ //
+ if (gFitTableContext.MicrocodeAlignment) {
+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) + MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
+ } else {
+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
+ }
+ }
+
+ //
+ // Add Microcode
+ //
+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+ printf ("-U Parameter incorrect, Too many Microcode!\n");
+ return 0;
+ }
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer);
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
+ gFitTableContext.MicrocodeNumber++;
+ gFitTableContext.FitEntryNumber++;
+
+ MicrocodeBuffer += MicrocodeSize;
+ }
+
+ if (MicrocodeFileBufferRaw != NULL) {
+ free ((VOID *)MicrocodeFileBufferRaw);
+ MicrocodeFileBufferRaw = NULL;
+ }
+ }
+
+ //
+ // 3.3 Microcode version
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-V") != 0) &&
+ (strcmp (argv[Index], "-v") != 0)) ) {
+ //
+ // Bypass
+ //
+ gFitTableContext.MicrocodeVersion = gFitTableContext.GlobalVersion;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.MicrocodeVersion = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+
+ //
+ // 4. Optional type
+ //
+ while (TRUE) {
+ if (Index + 2 >= argc) {
+ break;
+ }
+ if ((strcmp (argv[Index], "-O") != 0) &&
+ (strcmp (argv[Index], "-o") != 0) ) {
+ break;
+ }
+ Type = xtoi (argv[Index + 1]);
+ //
+ // 1st, try GUID
+ //
+ if (IsGuidData (argv[Index + 2], &Guid)) {
+ FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
+ if (FileBuffer == NULL) {
+ Error (NULL, 0, 0, "-O Parameter incorrect, GUID not found!", "%s", argv[Index + 2]);
+ // not found
+ return 0;
+ }
+ if (FileSize >= 0x80000000) {
+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+ return 0;
+ }
+ FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
+ Index += 3;
+ } else {
+ //
+ // 2nd, try file
+ //
+ Status = ReadInputFile (argv[Index + 2], &FileBuffer, &FileSize, NULL);
+ if (Status == STATUS_SUCCESS) {
+ if (FileSize >= 0x80000000) {
+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+ free (FileBuffer);
+ return 0;
+ }
+ //
+ // Set the most significant bit
+ // It means the data in memory, not in flash yet.
+ // Assume the file size should < 2G.
+ //
+ FileSize |= 0x80000000;
+ Index += 3;
+ } else {
+ //
+ // 3rd, try <RESERVE, Length>
+ //
+ if (Index + 3 >= argc) {
+ break;
+ }
+ if ((strcmp (argv[Index + 2], "RESERVE") == 0) ||
+ (strcmp (argv[Index + 2], "reserve") == 0)) {
+ FileSize = xtoi (argv[Index + 3]);
+ if (FileSize >= 0x80000000) {
+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+ return 0;
+ }
+ FileBuffer = malloc (FileSize);
+ if (FileBuffer == NULL) {
+ Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
+ return 0;
+ }
+ SetMem (FileBuffer, FileSize, 0xFF);
+ //
+ // Set the most significant bit
+ // It means the data in memory, not in flash yet.
+ // Assume the file size should < 2G.
+ //
+ FileSize |= 0x80000000;
+ Index += 4;
+ } else {
+ //
+ // 4th, try <Address, Length>
+ //
+ if (Index + 3 >= argc) {
+ break;
+ }
+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 2]);
+ FileSize = xtoi (argv[Index + 3]);
+ if (FileSize >= 0x80000000) {
+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+ return 0;
+ }
+ Index += 4;
+ }
+ }
+ }
+ if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) {
+ Error (NULL, 0, 0, "-O Parameter incorrect, Too many Optional Module!", NULL);
+ free (FileBuffer);
+ return 0;
+ }
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = Type;
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = FileSize;
+
+ //
+ // 4.1 Optional Module version
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-V") != 0) &&
+ (strcmp (argv[Index], "-v") != 0)) ) {
+ //
+ // Bypass
+ //
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = gFitTableContext.GlobalVersion;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+
+ gFitTableContext.OptionalModuleNumber ++;
+ gFitTableContext.FitEntryNumber++;
+ }
+
+ //
+ // 5. Port type
+ //
+ while (TRUE) {
+ if (Index + 6 >= argc) {
+ break;
+ }
+ if ((strcmp (argv[Index], "-P") != 0) &&
+ (strcmp (argv[Index], "-p") != 0) ) {
+ break;
+ }
+
+ Type = xtoi (argv[Index + 1]);
+ if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
+ printf ("-P Parameter incorrect, Too many Port Module!\n");
+ return 0;
+ }
+
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = Type;
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT16)xtoi (argv[Index + 2]) + ((UINT16)xtoi (argv[Index + 3]) << 16);
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT8)xtoi (argv[Index + 4]) + ((UINT8)xtoi (argv[Index + 5]) << 8) + ((UINT16)xtoi (argv[Index + 6]) << 16);
+ Index += 7;
+
+ //
+ // 5.1 Port Module version
+ //
+ if ((Index + 1 >= argc) ||
+ ((strcmp (argv[Index], "-V") != 0) &&
+ (strcmp (argv[Index], "-v") != 0)) ) {
+ //
+ // Bypass
+ //
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = 0;
+ } else {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = xtoi (argv[Index + 1]);
+ Index += 2;
+ }
+
+ gFitTableContext.PortModuleNumber++;
+ gFitTableContext.FitEntryNumber++;
+ }
+
+ //
+ // Final: Check StartupAcm in BiosModule.
+ //
+ CheckOverlap (gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size);
+ FitEntryNumber = gFitTableContext.FitEntryNumber;
+ for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) {
+ if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+ // NOTE: It might be virtual address now. Just put a place holder.
+ FitEntryNumber ++;
+ }
+ }
+
+ return FitEntryNumber;
+}
+
+VOID *
+FindSpaceSkipApVector (
+ IN UINT8 *FvBuffer,
+ IN UINT8 *Address,
+ IN UINTN Size
+ )
+/*++
+
+Routine Description:
+
+ No enough space - it might happen that it is occupied by AP wake vector.
+ Last chance - skip this and search again.
+
+Arguments:
+
+ FvBuffer - FvRecovery binary buffer
+ Address - Address to be searched from
+ Size - Size need to be filled
+
+Returns:
+
+ FitTableOffset - The FIT table offset
+ NULL - No enough space for FIT table
+
+*/
+{
+ UINT8 *ApVector;
+ UINT8 *NewAddress;
+ UINTN Index;
+
+ ApVector = (UINT8 *)((UINTN)Address & ~0xFFF);
+ if ((UINTN)ApVector <= (UINTN)FvBuffer) {
+ return NULL;
+ }
+
+ NewAddress = (UINT8 *)(ApVector - Size);
+ for (Index = 0; Index < Size; Index ++) {
+ if (NewAddress[Index] != 0xFF) {
+ return NULL;
+ }
+ }
+ return NewAddress;
+}
+
+VOID *
+GetFreeSpaceFromFv (
+ IN UINT8 *FvBuffer,
+ IN UINT32 FvSize,
+ IN UINT32 FitEntryNumber
+ )
+/*++
+
+Routine Description:
+
+ Get free space for FIT table from FvRecovery
+
+Arguments:
+
+ FvBuffer - FvRecovery binary buffer
+ FvSize - FvRecovery size
+ FitEntryNumber - The FIT entry number
+
+Returns:
+
+ FitTableOffset - The offset of FIT table in FvRecovery file
+ NULL - Free space not found
+
+--*/
+{
+ UINT8 *FitTableOffset;
+ INTN Index;
+ INTN SubIndex;
+ UINT8 *OptionalModuleAddress;
+ EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
+ UINT32 AlignedSize;
+ UINT32 FitTableSize;
+
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ UINT64 FvLength;
+ UINT32 Offset;
+ UINT32 FileLength;
+ UINT32 FileOccupiedSize;
+
+ //
+ // Check 4G - FitTablePointerOffset
+ //
+ if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xFFFFFFFFFFFFFFFFull) &&
+ (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0) &&
+ (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xEEEEEEEEEEEEEEEEull)) {
+ Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
+ return NULL;
+ }
+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
+ if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xFFFFFFFFFFFFFFFFull) &&
+ (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0) &&
+ (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xEEEEEEEEEEEEEEEEull)) {
+ Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
+ return NULL;
+ }
+ }
+
+ //
+ // Get EFI_FFS_VOLUME_TOP_FILE_GUID location
+ //
+ FitTableOffset = NULL;
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvBuffer;
+ FvLength = FvHeader->FvLength;
+ FileHeader = (EFI_FFS_FILE_HEADER *)(FvBuffer + FvHeader->HeaderLength);
+ Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
+
+ while (Offset < FvLength) {
+ FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
+ FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
+ if ((CompareGuid (&(FileHeader->Name), &VTFGuid)) == 0) {
+ // find it
+ FitTableOffset = (UINT8 *)FileHeader;
+ break;
+ }
+ FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize);
+ Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
+ }
+
+ if (FitTableOffset == NULL) {
+ Error (NULL, 0, 0, "EFI_FFS_VOLUME_TOP_FILE_GUID not found!", NULL);
+ return NULL;
+ }
+
+ FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
+ FitTableSize += FIT_ALIGNMENT;
+ FitTableSize &= ~FIT_ALIGNMENT;
+
+ FitTableOffset = (UINT8 *)((UINTN)FitTableOffset & ~FIT_ALIGNMENT);
+ FitTableOffset = (UINT8 *)(FitTableOffset - FitTableSize);
+
+ //
+ // Check it
+ //
+ for (Index = 0; Index < (INTN)(FitTableSize); Index ++) {
+ if (FitTableOffset[Index] != 0xFF) {
+ //
+ // No enough space - it might happen that it is occupied by AP wake vector.
+ // Last chance - skip this and search again.
+ //
+ FitTableOffset = FindSpaceSkipApVector (FvBuffer, &FitTableOffset[Index], FitTableSize);
+ if (FitTableOffset == NULL) {
+ Error (NULL, 0, 0, "No enough space for FIT table!", NULL);
+ return NULL;
+ }
+ }
+ }
+
+ //
+ // Check space for Optional module
+ //
+ OptionalModuleAddress = FitTableOffset;
+ for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) {
+ AlignedSize = gFitTableContext.OptionalModule[Index].Size;
+ if ((gFitTableContext.OptionalModule[Index].Size & 0x80000000) != 0) {
+
+ //
+ // Need copy binary to file.
+ //
+ gFitTableContext.OptionalModule[Index].Size &= ~0x80000000;
+
+ AlignedSize = gFitTableContext.OptionalModule[Index].Size;
+ if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+ // Let it 64 byte align
+ AlignedSize += BIOS_MODULE_ALIGNMENT;
+ AlignedSize &= ~BIOS_MODULE_ALIGNMENT;
+ }
+
+ OptionalModuleAddress -= AlignedSize;
+
+ if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+ // Let it 64 byte align
+ OptionalModuleAddress = (UINT8 *)((UINTN)OptionalModuleAddress & ~BIOS_MODULE_ALIGNMENT);
+ }
+
+ for (SubIndex = 0; SubIndex < (INTN)(AlignedSize); SubIndex ++) {
+ if (OptionalModuleAddress[SubIndex] != 0xFF) {
+ //
+ // No enough space - it might happen that it is occupied by AP wake vector.
+ // Last chance - skip this and search again.
+ //
+ OptionalModuleAddress = FindSpaceSkipApVector (FvBuffer, &OptionalModuleAddress[SubIndex], AlignedSize);
+ if (OptionalModuleAddress == NULL) {
+ Error (NULL, 0, 0, "No enough space for OptionalModule!", NULL);
+ return NULL;
+ }
+ }
+ }
+ memcpy (OptionalModuleAddress, (VOID *) (UINTN) gFitTableContext.OptionalModule[Index].Address, gFitTableContext.OptionalModule[Index].Size);
+ free ((VOID *) (UINTN) gFitTableContext.OptionalModule[Index].Address);
+ gFitTableContext.OptionalModule[Index].Address = MEMORY_TO_FLASH (OptionalModuleAddress, FvBuffer, FvSize);
+ }
+ //
+ // Final: Check BiosPolicyData in BiosModule.
+ //
+ if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+ (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+ CheckOverlap (gFitTableContext.OptionalModule[Index].Address, AlignedSize);
+ }
+ }
+
+ return FitTableOffset;
+}
+
+VOID
+PrintFitData (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Output FIT table information
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ UINT32 Index;
+
+ printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset);
+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
+ printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset2);
+ }
+ printf ("Total FIT Entry number: 0x%x\n", gFitTableContext.FitEntryNumber);
+ printf ("FitHeader version: 0x%04x\n", gFitTableContext.FitHeaderVersion);
+ if (gFitTableContext.StartupAcm.Address != 0) {
+ printf ("StartupAcm - (0x%08x, 0x%08x, 0x%04x)\n", gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size, gFitTableContext.StartupAcmVersion);
+ }
+ for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
+ printf ("BiosModule[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.BiosModule[Index].Address, gFitTableContext.BiosModule[Index].Size, gFitTableContext.BiosModuleVersion);
+ }
+ for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
+ printf ("Microcode[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.Microcode[Index].Address, gFitTableContext.Microcode[Index].Size, gFitTableContext.MicrocodeVersion);
+ }
+ for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) {
+ printf ("OptionalModule[%d] - (0x%08x, 0x%08x, 0x%02x, 0x%04x)\n", Index, gFitTableContext.OptionalModule[Index].Address, gFitTableContext.OptionalModule[Index].Size, gFitTableContext.OptionalModule[Index].Type, gFitTableContext.OptionalModule[Index].Version);
+ }
+ for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
+ printf ("PortModule[%d] - (0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%04x, 0x%02x, 0x%04x)\n", Index,
+ (UINT16)gFitTableContext.PortModule[Index].Address, (UINT16)(gFitTableContext.PortModule[Index].Address >> 16),
+ (UINT8)gFitTableContext.PortModule[Index].Size, (UINT8)(gFitTableContext.PortModule[Index].Size >> 8), (UINT16)(gFitTableContext.PortModule[Index].Size >> 16),
+ gFitTableContext.PortModule[Index].Type, gFitTableContext.PortModule[Index].Version);
+ }
+
+ printf ("\n");
+ return ;
+}
+
+CHAR8 *mFitTypeStr[] = {
+ " ",
+ "MICROCODE ",
+ "STARTUP_ACM",
+ " ",
+ " ",
+ " ",
+ " ",
+ "BIOS_MODULE",
+ "TPM_POLICY ",
+ "BIOS_POLICY",
+ "TXT_POLICY ",
+ "KEYMANIFEST",
+ "BP_MANIFEST",
+ "BIOS_DATA_A",
+ " ",
+ " ",
+ "CSE_SECUREB"
+};
+
+CHAR8 mFitSignature[] = "'_FIT_ ' ";
+CHAR8 mFitSignatureInHeader[] = "' ' ";
+CHAR8 *
+FitTypeToStr (
+ IN FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry
+ )
+/*++
+
+Routine Description:
+
+ Convert FitEntry type to a string
+
+Arguments:
+
+ FitEntry - Fit entry
+
+Returns:
+
+ String
+
+--*/
+{
+ if (FitEntry->Type == FIT_TABLE_TYPE_HEADER) {
+ CopyMem (&mFitSignatureInHeader[1], &FitEntry->Address, sizeof(FitEntry->Address));
+ return mFitSignatureInHeader;
+ }
+ if (FitEntry->Type < sizeof (mFitTypeStr)/sizeof(mFitTypeStr[0])) {
+ return mFitTypeStr[FitEntry->Type];
+ } else {
+ return " ";
+ }
+}
+
+VOID
+PrintFitTable (
+ IN UINT8 *FvBuffer,
+ IN UINT32 FvSize
+ )
+/*++
+
+Routine Description:
+
+ Print Fit table in flash image
+
+Arguments:
+
+ FvBuffer - FvRecovery binary buffer
+ FvSize - FvRecovery size
+
+Returns:
+
+ None
+
+--*/
+{
+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
+ UINT32 EntryNum;
+ UINT32 Index;
+ UINT32 FitTableOffset;
+ FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *FitEntryPort;
+
+ printf ("##############\n");
+ printf ("# FIT Table: #\n");
+ printf ("##############\n");
+
+ printf ("FIT Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset);
+ FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
+ printf ("FIT Table Address: 0x%x\n", FitTableOffset);
+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
+
+ //
+ // Check FitEntry is 16 byte aligned
+ //
+ if (((UINTN)FitEntry & 0xF) != 0) {
+ printf("ERROR: invalid FitEntry address 0x%X!\n", (UINT32) (UINTN) FitEntry);
+ return;
+ }
+
+ EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
+ printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+ printf ("Index: Address Size Version Type C_V Checksum (Index Data Width Bit Offset)\n");
+ printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+ for (Index = 0; Index < EntryNum; Index++) {
+ printf (" %02d: %016llx %06x %04x %02x-%s %02x %02x ",
+ Index,
+ (unsigned long long) FitEntry[Index].Address,
+ *(UINT32 *)(&FitEntry[Index].Size[0]) & 0xFFFFFF,
+ FitEntry[Index].Version,
+ FitEntry[Index].Type,
+ FitTypeToStr(&FitEntry[Index]),
+ FitEntry[Index].C_V,
+ FitEntry[Index].Checksum
+ );
+
+ if (Index == 0) {
+ if (FitEntry[Index].Type != FIT_TABLE_TYPE_HEADER) {
+ printf("ERROR: FIT Entry 0 is not Header Type %d!\n", FIT_TABLE_TYPE_HEADER);
+ return;
+ }
+ if (strcmp(mFitSignatureInHeader, mFitSignature) != 0) {
+ printf("ERROR: FIT Entry 0 signature invalid (%s, expected %s)!\n", mFitSignatureInHeader, mFitSignature);
+ return;
+ }
+
+ }
+
+ switch (FitEntry[Index].Type) {
+ case FIT_TABLE_TYPE_TPM_POLICY:
+ case FIT_TABLE_TYPE_TXT_POLICY:
+ if (FitEntry[Index].Version == 0) {
+ FitEntryPort = (FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *)&FitEntry[Index];
+ printf (" ( %04x %04x %02x %02x %04x )\n",
+ FitEntryPort->IndexPort,
+ FitEntryPort->DataPort,
+ FitEntryPort->Width,
+ FitEntryPort->Bit,
+ FitEntryPort->Index
+ );
+ break;
+ }
+ // Not Port Configure, pass through
+ default:
+ printf ("\n");
+ break;
+ }
+ }
+ printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+ printf ("Index: Address Size Version Type C_V Checksum (Index Data Width Bit Offset)\n");
+ printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+}
+
+/**
+
+ This function dump raw data.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+DumpData (
+ IN UINT8 *Data,
+ IN UINT32 Size
+ )
+{
+ UINT32 Index;
+ for (Index = 0; Index < Size; Index++) {
+ printf ("%02x", Data[Index]);
+ }
+}
+
+/**
+
+ This function dump raw data with colume format.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+DumpHex (
+ IN UINT8 *Data,
+ IN UINT32 Size
+ )
+{
+ UINT32 Index;
+ UINT32 Count;
+ UINT32 Left;
+
+#define COLUME_SIZE (16 * 2)
+
+ Count = Size / COLUME_SIZE;
+ Left = Size % COLUME_SIZE;
+ for (Index = 0; Index < Count; Index++) {
+ printf ("%04x: ", Index * COLUME_SIZE);
+ DumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
+ printf ("\n");
+ }
+
+ if (Left != 0) {
+ printf ("%04x: ", Index * COLUME_SIZE);
+ DumpData (Data + Index * COLUME_SIZE, Left);
+ printf ("\n");
+ }
+}
+
+//
+// This table defines the ACM type string
+//
+CHAR8 *mAcmTypeStr[] = {
+ "BIOS ACM",
+ "SINIT ACM",
+};
+
+//
+// This table defines the ACM capability string
+//
+CHAR8 *mCapabilityStr[] = {
+ "GETSEC[WAKEUP] for RLP ",
+ "MONITOR address for RLP ",
+ "ECX for MLE PageTable ",
+ "STM support ",
+};
+
+VOID
+DumpAcm (
+ IN ACM_FORMAT *Acm
+ )
+/*++
+
+Routine Description:
+
+ DumpAcm information
+
+Arguments:
+
+ Acm - ACM buffer
+
+Returns:
+
+ None
+
+--*/
+{
+ CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
+ CHIPSET_ID_LIST *ChipsetIdList;
+ PROCESSOR_ID_LIST *ProcessorIdList;
+ UINT32 Index;
+ UINT8 *Buffer;
+
+ printf (
+ "*****************************************************************************\n"
+ "* ACM *\n"
+ "*****************************************************************************\n"
+ );
+
+ printf ("ACM: (%08x)\n", (UINT32) (UINTN) Acm);
+ printf (" ModuleType - %04x\n", Acm->ModuleType);
+ if (Acm->ModuleType == ACM_MODULE_TYPE_CHIPSET_ACM) {
+ printf (" Chipset ACM\n");
+ }
+ printf (" ModuleSubType - %04x\n", Acm->ModuleSubType);
+ if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET) != 0) {
+ printf (" Capable of be Executed at Reset\n");
+ }
+ if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) != 0) {
+ printf (" AnC Module\n");
+ }
+ printf (" HeaderLen - %08x\n", Acm->HeaderLen);
+ printf (" HeaderVersion - %08x\n", Acm->HeaderVersion);
+ printf (" ChipsetID - %04x\n", Acm->ChipsetID);
+ printf (" Flags - %04x\n", Acm->Flags);
+ printf (" PreProduction - %04x\n", Acm->Flags & ACM_MODULE_FLAG_PREPRODUCTION);
+ printf (" Debug Signed - %04x\n", Acm->Flags & ACM_MODULE_FLAG_DEBUG_SIGN);
+ printf (" ModuleVendor - %08x\n", Acm->ModuleVendor);
+ printf (" Date - %08x\n", Acm->Date);
+ printf (" Size - %08x\n", Acm->Size);
+ printf (" TxtSvn - %04x\n", Acm->TxtSvn);
+ printf (" SeSvn - %04x\n", Acm->SeSvn);
+ printf (" CodeControl - %08x\n", Acm->CodeControl);
+ printf (" ErrorEntryPoint - %08x\n", Acm->ErrorEntryPoint);
+ printf (" GDTLimit - %08x\n", Acm->GDTLimit);
+ printf (" GDTBasePtr - %08x\n", Acm->GDTBasePtr);
+ printf (" SegSel - %08x\n", Acm->SegSel);
+ printf (" EntryPoint - %08x\n", Acm->EntryPoint);
+ printf (" KeySize - %08x\n", Acm->KeySize);
+ printf (" ScratchSize - %08x\n", Acm->ScratchSize);
+
+ Buffer = (UINT8 *)(Acm + 1);
+ printf (" RSAPubKey - \n");
+ DumpHex (Buffer, Acm->KeySize * 4);
+ printf ("\n");
+ Buffer += Acm->KeySize * 4;
+
+ if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
+ printf (" RSASig - \n");
+ DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE); // PKCS #1.5 RSA Signature
+ printf ("\n");
+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
+ } else {
+ printf (" RSAPubExp - %08x\n", *(UINT32 *)Buffer);
+ Buffer += 4;
+
+ printf (" RSASig - \n");
+ DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE); // PKCS #1.5 RSA Signature
+ printf ("\n");
+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
+ }
+ Buffer += Acm->ScratchSize * 4;
+
+ if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) {
+ ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer;
+ printf ("Chipset ACM info:\n");
+ printf (
+ " Guid - {%08x-%08x-%08x-%08x}\n",
+ ChipsetAcmInformationTable->Guid.Guid0,
+ ChipsetAcmInformationTable->Guid.Guid1,
+ ChipsetAcmInformationTable->Guid.Guid2,
+ ChipsetAcmInformationTable->Guid.Guid3
+ );
+ printf (" ChipsetACMType - %02x\n", ChipsetAcmInformationTable->ChipsetACMType);
+ if (ChipsetAcmInformationTable->ChipsetACMType < sizeof(mAcmTypeStr)/sizeof(mAcmTypeStr[0])) {
+ printf (" %s\n", mAcmTypeStr[ChipsetAcmInformationTable->ChipsetACMType]);
+ }
+ printf (" Version - %02x\n", ChipsetAcmInformationTable->Version);
+ printf (" Length - %04x\n", ChipsetAcmInformationTable->Length);
+ printf (" ChipsetIDList - %08x\n", ChipsetAcmInformationTable->ChipsetIDList);
+ printf (" OsSinitTableVer - %08x\n", ChipsetAcmInformationTable->OsSinitTableVer);
+ printf (" MinMleHeaderVer - %08x\n", ChipsetAcmInformationTable->MinMleHeaderVer);
+ if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
+ printf (" Capabilities - %08x\n", ChipsetAcmInformationTable->Capabilities);
+ for (Index = 0; Index < sizeof(mCapabilityStr)/sizeof(mCapabilityStr[0]); Index++) {
+ if (mCapabilityStr[Index] == NULL) {
+ continue;
+ }
+ printf (
+ " %s- %08x\n",
+ mCapabilityStr[Index],
+ (ChipsetAcmInformationTable->Capabilities & (1 << Index))
+ );
+ }
+ printf (" AcmVersion - %02x\n", ChipsetAcmInformationTable->AcmVersion);
+ printf (" AcmRevision - %02x.%02x.%02x\n", ChipsetAcmInformationTable->AcmRevision[0], ChipsetAcmInformationTable->AcmRevision[1], ChipsetAcmInformationTable->AcmRevision[2]);
+ }
+ if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
+ printf (" ProcessorIDList - %08x\n", ChipsetAcmInformationTable->ProcessorIDList);
+ }
+
+ ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList);
+ printf ("Chipset ID List info:\n");
+ printf (" Count - %08x\n", ChipsetIdList->Count);
+ for (Index = 0; Index < ChipsetIdList->Count; Index++) {
+ printf (" ID[%d]:\n", Index);
+ printf (" Flags - %08x\n", ChipsetIdList->ChipsetID[Index].Flags);
+ printf (" RevisionIdMask - %08x\n", ChipsetIdList->ChipsetID[Index].Flags & ACM_CHIPSET_ID_REVISION_ID_MAKE);
+ printf (" VendorID - %04x\n", ChipsetIdList->ChipsetID[Index].VendorID);
+ printf (" DeviceID - %04x\n", ChipsetIdList->ChipsetID[Index].DeviceID);
+ printf (" RevisionID - %04x\n", ChipsetIdList->ChipsetID[Index].RevisionID);
+ }
+ if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
+ goto End;
+ }
+ ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList);
+ printf ("Processor ID List info:\n");
+ printf (" Count - %08x\n", ProcessorIdList->Count);
+ for (Index = 0; Index < ProcessorIdList->Count; Index++) {
+ printf (" ID[%d]:\n", Index);
+ printf (" FMS - %08x\n", ProcessorIdList->ProcessorID[Index].FMS);
+ printf (" FMSMask - %08x\n", ProcessorIdList->ProcessorID[Index].FMSMask);
+ printf (" PlatformID - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformID);
+ printf (" PlatformMask - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformMask);
+ }
+ }
+
+End:
+ printf (
+ "*****************************************************************************\n\n"
+ );
+}
+
+BOOLEAN
+CheckAcm (
+ IN ACM_FORMAT *Acm,
+ IN UINTN AcmMaxSize
+ )
+/*++
+
+Routine Description:
+
+ Check Acm information
+
+Arguments:
+
+ Acm - ACM buffer
+ AcmMaxSize - ACM max size
+
+Returns:
+
+ TRUE - ACM is valid
+ FALSE - ACM is invalid
+
+--*/
+{
+ CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
+ CHIPSET_ID_LIST *ChipsetIdList;
+ PROCESSOR_ID_LIST *ProcessorIdList;
+ UINT8 *Buffer;
+
+ if (Acm->ModuleType != ACM_MODULE_TYPE_CHIPSET_ACM) {
+ printf ("ACM invalid : ModuleType!\n");
+ return FALSE;
+ }
+ if (Acm->Size * 4 > AcmMaxSize) {
+ printf ("ACM invalid : Size!\n");
+ return FALSE;
+ }
+
+ Buffer = (UINT8 *)(Acm + 1);
+ Buffer += Acm->KeySize * 4;
+ if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
+ } else {
+ Buffer += 4;
+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
+ }
+ Buffer += Acm->ScratchSize * 4;
+
+ if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) {
+ ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer;
+ if ((UINTN)ChipsetAcmInformationTable >= (UINTN)Acm + AcmMaxSize) {
+ printf ("ACM invalid : ChipsetAcmInformationTable!\n");
+ return FALSE;
+ }
+
+ if (CompareGuid ((EFI_GUID *)&ChipsetAcmInformationTable->Guid, (EFI_GUID *)&mChipsetAcmInformationTableGuid03) != 0) {
+ printf ("ACM invalid : ChipsetACMGuid!\n");
+ return FALSE;
+ }
+ if (ChipsetAcmInformationTable->ChipsetACMType != CHIPSET_ACM_TYPE_BIOS) {
+ printf ("ACM invalid : ChipsetACMType!\n");
+ return FALSE;
+ }
+ if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
+ printf ("ACM invalid : ChipsetACMVersion!\n");
+ return FALSE;
+ }
+ if ((UINTN)ChipsetAcmInformationTable + ChipsetAcmInformationTable->Length > (UINTN)Acm + AcmMaxSize) {
+ printf ("ACM invalid : ChipsetACMLength!\n");
+ return FALSE;
+ }
+
+ if (ChipsetAcmInformationTable->ChipsetIDList >= AcmMaxSize) {
+ printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
+ return FALSE;
+ }
+ ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList);
+ if (ChipsetIdList->Count == 0) {
+ printf ("ACM invalid : ChipsetACMChipsetIDListCount!\n");
+ return FALSE;
+ }
+ if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(CHIPSET_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_CHIPSET_ID) > AcmMaxSize) {
+ printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
+ return FALSE;
+ }
+
+ if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
+ goto End;
+ }
+
+ if (ChipsetAcmInformationTable->ProcessorIDList >= AcmMaxSize) {
+ printf ("ACM invalid : ChipsetACMProcessorIDList!\n");
+ return FALSE;
+ }
+ ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList);
+ if (ProcessorIdList->Count == 0) {
+ printf ("ACM invalid : ChipsetACMProcessorIdListCount!\n");
+ return FALSE;
+ }
+ if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(PROCESSOR_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_PROCESSOR_ID) > AcmMaxSize) {
+ printf ("ACM invalid : ChipsetACMProcessorIdList!\n");
+ return FALSE;
+ }
+ }
+
+End:
+
+ return TRUE;
+}
+
+VOID
+FillFitTable (
+ IN UINT8 *FvBuffer,
+ IN UINT32 FvSize,
+ IN UINT8 *FitTableOffset
+ )
+/*++
+
+Routine Description:
+
+ Fill the FIT table information to FvRecovery
+
+Arguments:
+
+ FvBuffer - FvRecovery binary buffer
+ FvSize - FvRecovery size
+ FitTableOffset - The offset of FIT table in FvRecovery file
+
+Returns:
+
+ None
+
+--*/
+{
+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
+ UINT32 FitIndex;
+ UINT32 Index;
+ UINT8 Checksum;
+ UINTN SubIndex;
+ FIT_TABLE_CONTEXT_ENTRY TempContextEntry;
+ FIRMWARE_INTERFACE_TABLE_ENTRY TempTableEntry;
+
+ //
+ // 1. FitPointer
+ //
+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
+ }
+
+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FitTableOffset;
+ FitIndex = 0;
+
+ //
+ // 2. FitHeader
+ //
+ FitEntry[FitIndex].Address = *(UINT64 *)"_FIT_ ";
+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.FitEntryNumber;
+ FitEntry[FitIndex].Version = (UINT16)gFitTableContext.FitHeaderVersion;
+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_HEADER;
+ FitEntry[FitIndex].C_V = 1;
+ //
+ // Checksum will be updated later...
+ //
+ FitEntry[FitIndex].Checksum = 0;
+
+ //
+ // 3. Microcode
+ //
+ FitIndex++;
+ for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
+ FitEntry[FitIndex].Address = gFitTableContext.Microcode[Index].Address;
+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.Microcode[Index].Size / 16;
+ FitEntry[FitIndex].Version = (UINT16)gFitTableContext.MicrocodeVersion;
+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_MICROCODE;
+ FitEntry[FitIndex].C_V = 0;
+ FitEntry[FitIndex].Checksum = 0;
+ FitIndex++;
+ }
+
+ //
+ // 4. StartupAcm
+ //
+ if (gFitTableContext.StartupAcm.Address != 0) {
+ FitEntry[FitIndex].Address = gFitTableContext.StartupAcm.Address;
+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.StartupAcm.Size / 16;
+ FitEntry[FitIndex].Version = (UINT16)gFitTableContext.StartupAcmVersion;
+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_STARTUP_ACM;
+ FitEntry[FitIndex].C_V = 0;
+ FitEntry[FitIndex].Checksum = 0;
+ FitIndex++;
+ }
+
+ //
+ // 5. BiosModule
+ //
+ //
+ // BiosModule segments order needs to be put from low addresss to high for Btg requirement
+ //
+ if (gFitTableContext.BiosModuleNumber > 1) {
+ for (Index = 0; Index < (UINTN)gFitTableContext.BiosModuleNumber - 1; Index++){
+ for (SubIndex = 0; SubIndex < gFitTableContext.BiosModuleNumber - Index - 1; SubIndex++) {
+ if (gFitTableContext.BiosModule[SubIndex].Address > gFitTableContext.BiosModule[SubIndex + 1].Address) {
+ CopyMem (&TempContextEntry, &gFitTableContext.BiosModule[SubIndex], sizeof(FIT_TABLE_CONTEXT_ENTRY));
+ CopyMem (&gFitTableContext.BiosModule[SubIndex], &gFitTableContext.BiosModule[SubIndex + 1], sizeof(FIT_TABLE_CONTEXT_ENTRY));
+ CopyMem (&gFitTableContext.BiosModule[SubIndex + 1], &TempContextEntry, sizeof(FIT_TABLE_CONTEXT_ENTRY));
+ }
+ }
+ }
+ }
+ for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
+ FitEntry[FitIndex].Address = gFitTableContext.BiosModule[Index].Address;
+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.BiosModule[Index].Size / 16;
+ FitEntry[FitIndex].Version = (UINT16)gFitTableContext.BiosModuleVersion;
+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_BIOS_MODULE;
+ FitEntry[FitIndex].C_V = 0;
+ FitEntry[FitIndex].Checksum = 0;
+ FitIndex++;
+ }
+
+ //
+ // 6. Optional module
+ //
+ for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) {
+ FitEntry[FitIndex].Address = gFitTableContext.OptionalModule[Index].Address;
+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.OptionalModule[Index].Size;
+ FitEntry[FitIndex].Version = (UINT16)gFitTableContext.OptionalModule[Index].Version;
+ FitEntry[FitIndex].Type = (UINT8)gFitTableContext.OptionalModule[Index].Type;
+ FitEntry[FitIndex].C_V = 0;
+ FitEntry[FitIndex].Checksum = 0;
+ FitIndex++;
+ }
+
+ //
+ // 7. Port module
+ //
+ for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
+ FitEntry[FitIndex].Address = gFitTableContext.PortModule[Index].Address + ((UINT64)gFitTableContext.PortModule[Index].Size << 32);
+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
+ FitEntry[FitIndex].Version = (UINT16)gFitTableContext.PortModule[Index].Version;
+ FitEntry[FitIndex].Type = (UINT8)gFitTableContext.PortModule[Index].Type;
+ FitEntry[FitIndex].C_V = 0;
+ FitEntry[FitIndex].Checksum = 0;
+ FitIndex++;
+ }
+
+ //
+ // The FIT records must always be arranged in the ascending order of their type attribute in the FIT.
+ //
+ for (Index = 0; Index < (UINTN)FitIndex - 1; Index++){
+ for (SubIndex = 0; SubIndex < FitIndex - Index - 1; SubIndex++) {
+ if (FitEntry[SubIndex].Type > FitEntry[SubIndex + 1].Type) {
+ CopyMem (&TempTableEntry, &FitEntry[SubIndex], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
+ CopyMem (&FitEntry[SubIndex], &FitEntry[SubIndex + 1], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
+ CopyMem (&FitEntry[SubIndex + 1], &TempTableEntry, sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
+ }
+ }
+ }
+
+ //
+ // Update FIT header signature as final step
+ //
+ Checksum = CalculateChecksum8 ((UINT8 *)&FitEntry[0], sizeof (FIRMWARE_INTERFACE_TABLE_ENTRY) * FitIndex);
+ FitEntry[0].Checksum = Checksum;
+}
+
+VOID
+ClearFitTable (
+ IN UINT8 *FvBuffer,
+ IN UINT32 FvSize
+ )
+/*++
+
+Routine Description:
+
+ Clear the FIT table information to Fvrecovery
+
+Arguments:
+
+ FvBuffer - Fvrecovery binary buffer
+ FvSize - Fvrecovery size
+
+Returns:
+
+ None
+
+--*/
+{
+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
+ UINT32 EntryNum;
+ UINT32 FitIndex;
+ UINT64 FitTablePointer;
+ UINT8 *Buffer;
+ UINT32 BufferSize;
+
+ FitTablePointer = *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY (FitTablePointer, FvBuffer, FvSize);
+
+ //
+ // Clear FIT pointer
+ //
+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = 0xEEEEEEEEEEEEEEEEull;
+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = 0xEEEEEEEEEEEEEEEEull;
+ }
+
+ //
+ // Clear FIT table
+ //
+ EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
+ for (FitIndex = 0; FitIndex < EntryNum; FitIndex++) {
+ switch (FitEntry[FitIndex].Type) {
+ case FIT_TABLE_TYPE_BIOS_POLICY:
+ case FIT_TABLE_TYPE_KEY_MANIFEST:
+ case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
+ case FIT_TABLE_TYPE_BIOS_DATA_AREA:
+ case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
+ //
+ // Clear FIT table data buffer
+ //
+ Buffer = FLASH_TO_MEMORY (FitEntry[FitIndex].Address, FvBuffer, FvSize);
+ BufferSize = (*(UINT32 *)FitEntry[FitIndex].Size) & 0xFFFFFF;
+ SetMem (Buffer, BufferSize, 0xFF);
+ break;
+ default:
+ break;
+ }
+ //
+ // Clear FIT table itself
+ //
+ SetMem (&FitEntry[FitIndex], sizeof(FitEntry[FitIndex]), 0xFF);
+ }
+}
+
+STATUS
+WriteOutputFile (
+ IN CHAR8 *FileName,
+ IN UINT8 *FileData,
+ IN UINT32 FileSize
+ )
+/*++
+
+Routine Description:
+
+ Read input file
+
+Arguments:
+
+ FileName - The input file name
+ FileData - The input file data
+ FileSize - The input file size
+
+Returns:
+
+ STATUS_SUCCESS - Write file data successfully
+ STATUS_ERROR - The file data is not written
+
+--*/
+{
+ FILE *FpOut;
+
+ //
+ // Open the output FvRecovery.fv file
+ //
+ if ((FpOut = fopen (FileName, "w+b")) == NULL) {
+ Error (NULL, 0, 0, "Unable to open file", "%s", FileName);
+ return STATUS_ERROR;
+ }
+ //
+ // Write the output FvRecovery.fv file
+ //
+ if ((fwrite (FileData, 1, FileSize, FpOut)) != FileSize) {
+ Error (NULL, 0, 0, "Write output file error!", NULL);
+ fclose (FpOut);
+ return STATUS_ERROR;
+ }
+
+ //
+ // Close the output FvRecovery.fv file
+ //
+ fclose (FpOut);
+
+ return STATUS_SUCCESS;
+}
+
+UINT32
+GetFvRecoveryInfoFromFd (
+ IN UINT8 *FdBuffer,
+ IN UINT32 FdFileSize,
+ OUT UINT8 **FvRecovery
+ )
+/*++
+
+Routine Description:
+
+ Get FvRecovery information from Fd file.
+
+Arguments:
+
+ FdBuffer - Fd file buffer.
+ FdFileSize - Fd file size.
+ FvRecovery - FvRecovery pointer in Fd file buffer
+
+Returns:
+ FvRecovery file size
+
+--*/
+{
+ UINT8 *FileBuffer = NULL;
+ UINT32 FvRecoveryFileSize =0;
+ EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
+ UINT32 FvLength;
+ UINT32 FileLength;
+
+ *FvRecovery = NULL;
+ FileBuffer = FindNextFvHeader (FdBuffer, FdFileSize);
+ if (FileBuffer == NULL) {
+ return 0;
+ }
+
+ while ((UINTN)FileBuffer < (UINTN)FdBuffer + FdFileSize) {
+ FvLength = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->FvLength;
+
+ if (FindFileFromFvByGuid (FileBuffer, FvLength, &VTFGuid, &FileLength) != NULL) {
+ //
+ // Found the VTF
+ //
+ FvRecoveryFileSize = FvLength;
+ *FvRecovery = FileBuffer;
+ }
+
+ //
+ // Next fv
+ //
+ FileBuffer = (UINT8 *)FileBuffer + FvLength;
+ if ((UINTN)FileBuffer >= (UINTN)FdBuffer + FdFileSize) {
+ break;
+ }
+ FileBuffer = FindNextFvHeader (FileBuffer, (UINTN)FdBuffer + FdFileSize - (UINTN)FileBuffer);
+ if (FileBuffer == NULL) {
+ break;
+ }
+
+ }
+
+ //
+ // Return
+ //
+ return FvRecoveryFileSize;
+}
+
+UINT32
+GetFitEntryInfo (
+ IN UINT8 *FvBuffer,
+ IN UINT32 FvSize
+ )
+/*++
+
+Routine Description:
+
+ Fill the FIT table information to Fvrecovery
+
+Arguments:
+
+ FvBuffer - Fvrecovery binary buffer
+ FvSize - Fvrecovery size
+
+Returns:
+
+ 0 - Fit Table not found
+
+--*/
+{
+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
+ UINT32 FitIndex;
+ UINT32 FitTableOffset;
+
+ //
+ // 1. FitPointer
+ //
+ if (gFitTableContext.FitTablePointerOffset == 0) {
+ gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
+ }
+ gFitTableContext.FitTablePointerOffset2 = 0;
+
+ FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
+
+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
+ FitIndex = 0;
+
+ //
+ // 2. FitHeader
+ //
+ if (FitEntry[FitIndex].Address != *(UINT64 *)"_FIT_ ") {
+ return 0;
+ }
+ if (FitEntry[FitIndex].Type != FIT_TABLE_TYPE_HEADER) {
+ return 0;
+ }
+ gFitTableContext.FitEntryNumber = *(UINT32 *)&FitEntry[FitIndex].Size[0];
+ gFitTableContext.FitHeaderVersion = FitEntry[FitIndex].Version;
+
+ //
+ // 3. FitEntry
+ //
+ FitIndex++;
+ for (; FitIndex < gFitTableContext.FitEntryNumber; FitIndex++) {
+ switch (FitEntry[FitIndex].Type) {
+ case FIT_TABLE_TYPE_MICROCODE:
+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+ gFitTableContext.MicrocodeVersion = FitEntry[FitIndex].Version;
+ gFitTableContext.MicrocodeNumber ++;
+ break;
+ case FIT_TABLE_TYPE_STARTUP_ACM:
+ gFitTableContext.StartupAcm.Address = (UINT32)FitEntry[FitIndex].Address;
+ gFitTableContext.StartupAcmVersion = FitEntry[FitIndex].Version;
+ break;
+ case FIT_TABLE_TYPE_BIOS_MODULE:
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = *(UINT32 *)&FitEntry[FitIndex].Size[0] * 16;
+ gFitTableContext.BiosModuleVersion = FitEntry[FitIndex].Version;
+ gFitTableContext.BiosModuleNumber ++;
+ break;
+ case FIT_TABLE_TYPE_TPM_POLICY:
+ case FIT_TABLE_TYPE_TXT_POLICY:
+ if (FitEntry[FitIndex].Version == 0) {
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT32)(FitEntry[FitIndex].Address >> 32);
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = FitEntry[FitIndex].Version;
+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = FitEntry[FitIndex].Type;
+ gFitTableContext.PortModuleNumber ++;
+ break;
+ }
+ // Not Port Configure, pass through
+ default: // Others
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = *(UINT32 *)&FitEntry[FitIndex].Size[0];
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = FitEntry[FitIndex].Version;
+ gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = FitEntry[FitIndex].Type;
+ gFitTableContext.OptionalModuleNumber ++;
+ break;
+ }
+ }
+
+ return gFitTableContext.FitEntryNumber;
+}
+
+STATUS
+FitGen (
+ IN INTN argc,
+ IN CHAR8 **argv
+ )
+/*++
+
+Routine Description:
+
+ Main function for FitGen.
+
+Arguments:
+
+ argc - Number of command line parameters.
+ argv - Array of pointers to parameter strings.
+
+Returns:
+ STATUS_SUCCESS - Utility exits successfully.
+ STATUS_ERROR - Some error occurred during execution.
+
+--*/
+{
+ UINT32 FvRecoveryFileSize;
+ UINT8 *FileBuffer;
+ UINT8 *FileBufferRaw;
+ UINTN FitEntryNumber;
+ UINT8 *FitTableOffset;
+ STATUS Status;
+ UINT32 FitTableSize;
+
+ BOOLEAN IsFv;
+ UINT8 *FdFileBuffer;
+ UINT32 FdFileSize;
+
+ UINT8 *AcmBuffer;
+
+ //
+ // Step 0: Check FV or FD
+ //
+ if (((strcmp (argv[1], "-D") == 0) ||
+ (strcmp (argv[1], "-d") == 0)) ) {
+ IsFv = FALSE;
+ } else {
+ IsFv = TRUE;
+ }
+
+ //
+ // Step 1: Read InputFvRecovery.fv data
+ //
+ if (IsFv) {
+ Status = ReadInputFile (argv[1], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw);
+ if (Status != STATUS_SUCCESS) {
+ Error (NULL, 0, 0, "Unable to open file", "%s", argv[1]);
+ goto exitFunc;
+ }
+ FdFileBuffer = FileBuffer;
+ FdFileSize = FvRecoveryFileSize;
+ } else {
+ Status = ReadInputFile (argv[2], &FdFileBuffer, &FdFileSize, &FileBufferRaw);
+ if (Status != STATUS_SUCCESS) {
+ Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
+ goto exitFunc;
+ }
+
+ //
+ // Get Fvrecovery information
+ //
+ FvRecoveryFileSize = GetFvRecoveryInfoFromFd (FdFileBuffer, FdFileSize, &FileBuffer);
+ if ((FvRecoveryFileSize == 0) || (FileBuffer == NULL)) {
+ Error (NULL, 0, 0, "FvRecovery not found in Fd file!", NULL);
+ Status = STATUS_ERROR;
+ goto exitFunc;
+ }
+ }
+
+ //
+ // Step 2: Calculate FIT entry number.
+ //
+ FitEntryNumber = GetFitEntryNumber (argc, argv, FdFileBuffer, FdFileSize);
+ if (!gFitTableContext.Clear) {
+ if (FitEntryNumber == 0) {
+ Status = STATUS_ERROR;
+ goto exitFunc;
+ }
+
+ //
+ // For debug
+ //
+ PrintFitData ();
+
+ //
+ // Add 1 more FitEntry as place holder, because we need exclude FIT table itself
+ //
+ FitEntryNumber++;
+
+ //
+ // Step 3: Get enough space in FvRecovery.fv
+ //
+ FitTableOffset = GetFreeSpaceFromFv (FileBuffer, FvRecoveryFileSize, FitEntryNumber);
+ if (FitTableOffset == NULL) {
+ return STATUS_ERROR;
+ }
+ FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
+ FitTableSize += FIT_ALIGNMENT;
+ FitTableSize &= ~FIT_ALIGNMENT;
+
+ CheckOverlap (
+ MEMORY_TO_FLASH (FitTableOffset, FdFileBuffer, FdFileSize),
+ FitTableSize
+ );
+
+ //
+ // Get ACM buffer
+ //
+ if (gFitTableContext.StartupAcm.Address != 0) {
+ AcmBuffer = FLASH_TO_MEMORY(gFitTableContext.StartupAcm.Address, FdFileBuffer, FdFileSize);
+ if ((AcmBuffer < FdFileBuffer) || (AcmBuffer + gFitTableContext.StartupAcm.Size > FdFileBuffer + FdFileSize)) {
+ printf ("ACM out of range - can not validate it\n");
+ AcmBuffer = NULL;
+ }
+
+ if (AcmBuffer != NULL) {
+ if (CheckAcm ((ACM_FORMAT *)AcmBuffer, gFitTableContext.StartupAcm.Size)) {
+ DumpAcm ((ACM_FORMAT *)AcmBuffer);
+ } else {
+ Status = STATUS_ERROR;
+ goto exitFunc;
+ }
+ }
+
+ }
+
+ //
+ // Step 4: Fill the FIT table one by one
+ //
+ FillFitTable (FdFileBuffer, FdFileSize, FitTableOffset);
+
+ //
+ // For debug
+ //
+ PrintFitTable (FdFileBuffer, FdFileSize);
+ } else {
+ printf ("Clear FIT table ...\n");
+ //
+ // Step 3: Get FIT table info
+ //
+ FitEntryNumber = GetFitEntryInfo (FdFileBuffer, FdFileSize);
+ if (FitEntryNumber == 0) {
+ Error (NULL, 0, 0, "No FIT table found", NULL);
+ return STATUS_ERROR;
+ }
+
+ //
+ // For debug
+ //
+ PrintFitTable (FdFileBuffer, FdFileSize);
+
+ //
+ // Step 4: Clear FIT table
+ //
+ ClearFitTable (FdFileBuffer, FdFileSize);
+ printf ("Clear FIT table Done!\n");
+ }
+
+ //
+ // Step 5: Write OutputFvRecovery.fv data
+ //
+ if (IsFv) {
+ Status = WriteOutputFile (argv[2], FileBuffer, FvRecoveryFileSize);
+ } else {
+ Status = WriteOutputFile (argv[3], FdFileBuffer, FdFileSize);
+ }
+
+exitFunc:
+ if (FileBufferRaw != NULL) {
+ free ((VOID *)FileBufferRaw);
+ }
+ return Status;
+}
+
+STATUS
+FitView (
+ IN INTN argc,
+ IN CHAR8 **argv
+ )
+/*++
+
+Routine Description:
+
+ View function for FitGen.
+
+Arguments:
+
+ argc - Number of command line parameters.
+ argv - Array of pointers to parameter strings.
+
+Returns:
+ STATUS_SUCCESS - Utility exits successfully.
+ STATUS_ERROR - Some error occurred during execution.
+
+--*/
+{
+ UINT32 FvRecoveryFileSize;
+ UINT8 *FileBuffer;
+ UINT8 *FileBufferRaw = NULL;
+ STATUS Status;
+
+ //
+ // Step 1: Read input file
+ //
+ Status = ReadInputFile (argv[2], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw);
+ if (Status != STATUS_SUCCESS) {
+ Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
+ goto exitFunc;
+ }
+
+ // no -f option, use default FIT pointer offset
+ if (argc == 3) {
+ //
+ // Use default address
+ //
+ gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
+ } else if (stricmp (argv[3], "-f") == 0) {
+ if (argc == 5) {
+ //
+ // Get offset from parameter
+ //
+ gFitTableContext.FitTablePointerOffset = xtoi (argv[3 + 1]);
+ } else {
+ Error (NULL, 0, 0, "FIT offset not specified!", NULL);
+ goto exitFunc;
+ }
+ } else {
+ Error (NULL, 0, 0, "Invalid view option: ", "%s", argv[3]);
+ goto exitFunc;
+ }
+
+ //
+ // For debug
+ //
+ PrintFitTable (FileBuffer, FvRecoveryFileSize);
+
+exitFunc:
+ if (FileBufferRaw != NULL) {
+ free ((VOID *)FileBufferRaw);
+ }
+ return Status;
+}
+
+int
+main (
+ int argc,
+ char **argv
+ )
+/*++
+
+Routine Description:
+
+ Main function.
+
+Arguments:
+
+ argc - Number of command line parameters.
+ argv - Array of pointers to parameter strings.
+
+Returns:
+ STATUS_SUCCESS - Utility exits successfully.
+ STATUS_ERROR - Some error occurred during execution.
+
+--*/
+{
+ SetUtilityName (UTILITY_NAME);
+
+ //
+ // Display utility information
+ //
+ PrintUtilityInfo ();
+
+ //
+ // Verify the correct number of arguments
+ //
+ if (argc >= MIN_VIEW_ARGS && stricmp (argv[1], "-view") == 0) {
+ return FitView (argc, argv);
+ } else if (argc >= MIN_ARGS) {
+ return FitGen (argc, argv);
+ } else {
+ Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);
+ PrintUsage ();
+ return STATUS_ERROR;
+ }
+}
+
+unsigned int
+xtoi (
+ char *str
+ )
+/*++
+
+Routine Description:
+
+ Convert hex string to uint
+
+Arguments:
+
+ str - The string
+
+Returns:
+
+--*/
+{
+ unsigned int u;
+ char c;
+ unsigned int m;
+
+ if (str == NULL) {
+ return 0;
+ }
+
+ m = (unsigned int) -1 >> 4;
+ //
+ // skip preceeding white space
+ //
+ while (*str && *str == ' ') {
+ str += 1;
+ }
+ //
+ // skip preceeding zeros
+ //
+ while (*str && *str == '0') {
+ str += 1;
+ }
+ //
+ // skip preceeding x/X character
+ //
+ if (*str && (*str == 'x' || *str == 'X')) {
+ str += 1;
+ }
+ //
+ // convert hex digits
+ //
+ u = 0;
+ c = *(str++);
+ while (c) {
+ if (c >= 'a' && c <= 'f') {
+ c -= 'a' - 'A';
+ }
+
+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
+ if (u > m) {
+ return (unsigned int) -1;
+ }
+
+ u = (u << 4) | (c - (c >= 'A' ? 'A' - 10 : '0'));
+ } else {
+ //
+ // Let application exit immediately
+ //
+ Error (NULL, 0, 0, "Hex value is expected!", NULL);
+ exit (0);
+ break;
+ }
+
+ c = *(str++);
+ }
+
+ return u;
+}
+
diff --git a/Silicon/Intel/Tools/FitGen/FitGen.h b/Silicon/Intel/Tools/FitGen/FitGen.h
new file mode 100644
index 0000000000..9bd3f6824b
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/FitGen.h
@@ -0,0 +1,48 @@
+/**@file
+Definitions for the FitGen utility.
+
+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FIT_GEN_H
+#define _FIT_GEN_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#define PI_SPECIFICATION_VERSION 0x00010000
+#define EFI_FVH_PI_REVISION EFI_FVH_REVISION
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include "EfiUtilityMsgs.c"
+#include "CommonLib.h"
+#include "ParseInf.h"
+#include "FvLib.h"
+
+//
+// Utility Name
+//
+#define UTILITY_NAME "FitGen"
+
+//
+// Utility version information
+//
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 56
+#define UTILITY_DATE __DATE__
+
+//
+// The minimum number of arguments accepted from the command line.
+//
+#define MIN_VIEW_ARGS 3
+#define MIN_ARGS 4
+#define BUF_SIZE (8 * 1024)
+
+#define GETOCCUPIEDSIZE(ActualSize, Alignment) \
+ (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
+;
+
+#endif
diff --git a/Silicon/Intel/Tools/FitGen/GNUmakefile b/Silicon/Intel/Tools/FitGen/GNUmakefile
new file mode 100644
index 0000000000..00a99bb0c7
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/GNUmakefile
@@ -0,0 +1,16 @@
+# @file
+# GNUmakefile for building the FitGen utility.
+#
+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = FitGen
+
+OBJECTS = FitGen.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
+LIBS = -lCommon
+
diff --git a/Silicon/Intel/Tools/FitGen/Makefile b/Silicon/Intel/Tools/FitGen/Makefile
new file mode 100644
index 0000000000..fd286b26be
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/Makefile
@@ -0,0 +1,17 @@
+# @file
+# makefile for building the FitGen utility.
+#
+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = FitGen
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = FitGen.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [edk2-devel] [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen
2019-06-21 1:26 ` [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Zhang, Shenglei
@ 2019-06-26 2:03 ` Liming Gao
0 siblings, 0 replies; 15+ messages in thread
From: Liming Gao @ 2019-06-26 2:03 UTC (permalink / raw)
To: devel@edk2.groups.io, Zhang, Shenglei; +Cc: Feng, Bob C
Shenglei:
The patch is good to me. Reviewed-by: Liming Gao <liming.gao@intel.com>
Thanks
Liming
>-----Original Message-----
>From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
>Zhang, Shenglei
>Sent: Friday, June 21, 2019 9:27 AM
>To: devel@edk2.groups.io
>Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>
>Subject: [edk2-devel] [edk2-platform patch 5/6] Silicon\Tools: Add a tool
>FitGen
>
>The utility of this tool is part of build process for IA32/X64 FD.
>It generates FIT table.
>https://bugzilla.tianocore.org/show_bug.cgi?id=1849
>
>Cc: Bob Feng <bob.c.feng@intel.com>
>Cc: Liming Gao <liming.gao@intel.com>
>Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
>---
> Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++++++++++++++++++
> Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
> Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
> Silicon/Intel/Tools/FitGen/Makefile | 17 +
> 4 files changed, 3218 insertions(+)
> create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
>
>diff --git a/Silicon/Intel/Tools/FitGen/FitGen.c
>b/Silicon/Intel/Tools/FitGen/FitGen.c
>new file mode 100644
>index 0000000000..faf9880060
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/FitGen.c
>@@ -0,0 +1,3137 @@
>+/**@file
>+This utility is part of build process for IA32/X64 FD.
>+It generates FIT table.
>+
>+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+SPDX-License-Identifier: BSD-2-Clause-Patent
>+
>+**/
>+
>+#include "FitGen.h"
>+
>+//
>+// FIT spec
>+//
>+#pragma pack (1)
>+typedef struct {
>+ UINT64 Address;
>+ UINT8 Size[3];
>+ UINT8 Rsvd;
>+ UINT16 Version;
>+ UINT8 Type:7;
>+ UINT8 C_V:1;
>+ UINT8 Checksum;
>+} FIRMWARE_INTERFACE_TABLE_ENTRY;
>+
>+//
>+// Struct for policy
>+//
>+typedef struct {
>+ UINT16 IndexPort;
>+ UINT16 DataPort;
>+ UINT8 Width;
>+ UINT8 Bit;
>+ UINT16 Index;
>+ UINT8 Size[3];
>+ UINT8 Rsvd;
>+ UINT16 Version; // == 0
>+ UINT8 Type:7;
>+ UINT8 C_V:1;
>+ UINT8 Checksum;
>+} FIRMWARE_INTERFACE_TABLE_ENTRY_PORT;
>+
>+#define FIT_ALIGNMENT 0x3F // 0xF is required previously, but if we
>need exclude FIT, we must set 64 bytes alignment.
>+#define BIOS_MODULE_ALIGNMENT 0x3F // 64 bytes for AnC
>+#define MICROCODE_ALIGNMENT 0x7FF
>+
>+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE 256
>+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE 384
>+
>+#define ACM_HEADER_VERSION_3 (3 << 16)
>+#define ACM_MODULE_TYPE_CHIPSET_ACM 2
>+#define ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET 0x1
>+#define ACM_MODULE_SUBTYPE_ANC_MODULE 0x2
>+#define ACM_MODULE_FLAG_PREPRODUCTION 0x4000
>+#define ACM_MODULE_FLAG_DEBUG_SIGN 0x8000
>+
>+
>+typedef struct {
>+ UINT16 ModuleType;
>+ UINT16 ModuleSubType;
>+ UINT32 HeaderLen;
>+ UINT32 HeaderVersion;
>+ UINT16 ChipsetID;
>+ UINT16 Flags;
>+ UINT32 ModuleVendor;
>+ UINT32 Date;
>+ UINT32 Size;
>+ UINT16 TxtSvn;
>+ UINT16 SeSvn;
>+ UINT32 CodeControl;
>+ UINT32 ErrorEntryPoint;
>+ UINT32 GDTLimit;
>+ UINT32 GDTBasePtr;
>+ UINT32 SegSel;
>+ UINT32 EntryPoint;
>+ UINT8 Rsvd2[64];
>+ UINT32 KeySize; // 64
>+ UINT32 ScratchSize; // 2 * KeySize + 15
>+//UINT8 RSAPubKey[64 * 4]; // KeySize * 4
>+//UINT32 RSAPubExp;
>+//UINT8 RSASig[256];
>+ // End of AC module header
>+//UINT8 Scratch[(64 * 2 + 15) * 4]; // ScratchSize * 4
>+ // User Area
>+//UINT8 UserArea[1];
>+} ACM_FORMAT;
>+
>+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_3 0x03
>+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_4 0x04
>+
>+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3
>+
>+#define CHIPSET_ACM_INFORMATION_TABLE_GUID_V03 \
>+ { 0x7FC03AAA, 0x18DB46A7, 0x8F69AC2E, 0x5A7F418D }
>+
>+#define CHIPSET_ACM_TYPE_BIOS 0
>+#define CHIPSET_ACM_TYPE_SINIT 1
>+
>+typedef struct {
>+ UINT32 Guid0;
>+ UINT32 Guid1;
>+ UINT32 Guid2;
>+ UINT32 Guid3;
>+} ACM_GUID;
>+
>+typedef struct {
>+ ACM_GUID Guid;
>+ UINT8 ChipsetACMType;
>+ UINT8 Version;
>+ UINT16 Length;
>+ UINT32 ChipsetIDList;
>+ UINT32 OsSinitTableVer;
>+ UINT32 MinMleHeaderVer;
>+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3)
>+ UINT32 Capabilities;
>+ UINT8 AcmVersion;
>+ UINT8 AcmRevision[3];
>+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4)
>+ UINT32 ProcessorIDList;
>+//#endif
>+//#endif
>+} CHIPSET_ACM_INFORMATION_TABLE;
>+
>+#define ACM_CHIPSET_ID_REVISION_ID_MAKE 0x1
>+
>+typedef struct {
>+ UINT32 Flags;
>+ UINT16 VendorID;
>+ UINT16 DeviceID;
>+ UINT16 RevisionID;
>+ UINT8 Reserved[6];
>+} ACM_CHIPSET_ID;
>+
>+typedef struct {
>+ UINT32 Count;
>+ ACM_CHIPSET_ID ChipsetID[1];
>+} CHIPSET_ID_LIST;
>+
>+typedef struct {
>+ UINT32 FMS;
>+ UINT32 FMSMask;
>+ UINT64 PlatformID;
>+ UINT64 PlatformMask;
>+} ACM_PROCESSOR_ID;
>+
>+typedef struct {
>+ UINT32 Count;
>+ ACM_PROCESSOR_ID ProcessorID[1];
>+} PROCESSOR_ID_LIST;
>+
>+#pragma pack ()
>+
>+
>+ACM_GUID mChipsetAcmInformationTableGuid03 =
>CHIPSET_ACM_INFORMATION_TABLE_GUID_V03;
>+
>+
>+//
>+// BIOS INFO data structure
>+// This is self contained data structure for BIOS info
>+//
>+#pragma pack (1)
>+#define BIOS_INFO_SIGNATURE SIGNATURE_64 ('$', 'B', 'I', 'O', 'S', 'I', 'F', '$')
>+typedef struct {
>+ UINT64 Signature;
>+ UINT32 EntryCount;
>+ UINT32 Reserved;
>+//BIOS_INFO_STRUCT Struct[EntryCount];
>+} BIOS_INFO_HEADER;
>+
>+//
>+// BIOS_INFO_STRUCT attributes
>+// bits[0:3] means general attributes
>+// bits[4:7] means type specific attributes
>+//
>+#define BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT
>0x01
>+#define BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION
>0x10
>+#define BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB 0x10
>+
>+typedef struct {
>+ //
>+ // FitTable entry type
>+ //
>+ UINT8 Type;
>+ //
>+ // BIOS_INFO_STRUCT attributes
>+ //
>+ UINT8 Attributes;
>+ //
>+ // FitTable entry version
>+ //
>+ UINT16 Version;
>+ //
>+ // FitTable entry real size
>+ //
>+ UINT32 Size;
>+ //
>+ // FitTable entry address
>+ //
>+ UINT64 Address;
>+} BIOS_INFO_STRUCT;
>+
>+#pragma pack ()
>+
>+#define MAX_BIOS_MODULE_ENTRY 0x20
>+#define MAX_MICROCODE_ENTRY 0x20
>+#define MAX_OPTIONAL_ENTRY 0x20
>+#define MAX_PORT_ENTRY 0x20
>+
>+#define DEFAULT_FIT_TABLE_POINTER_OFFSET 0x40
>+#define DEFAULT_FIT_ENTRY_VERSION 0x0100
>+
>+#define MEMORY_TO_FLASH(FileBuffer, FvBuffer, FvSize) \
>+ (UINTN)(0x100000000 - ((UINTN)(FvBuffer) + (UINTN)(FvSize) -
>(UINTN)(FileBuffer)))
>+#define FLASH_TO_MEMORY(Address, FvBuffer, FvSize) \
>+ (VOID *)(UINTN)((UINTN)(FvBuffer) + (UINTN)(FvSize) -
>(0x100000000 - (UINTN)(Address)))
>+
>+#define FIT_TABLE_TYPE_HEADER 0
>+#define FIT_TABLE_TYPE_MICROCODE 1
>+#define FIT_TABLE_TYPE_STARTUP_ACM 2
>+#define FIT_TABLE_TYPE_BIOS_MODULE 7
>+#define FIT_TABLE_TYPE_TPM_POLICY 8
>+#define FIT_TABLE_TYPE_BIOS_POLICY 9
>+#define FIT_TABLE_TYPE_TXT_POLICY 10
>+#define FIT_TABLE_TYPE_KEY_MANIFEST 11
>+#define FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST 12
>+#define FIT_TABLE_TYPE_BIOS_DATA_AREA 13
>+#define FIT_TABLE_TYPE_CSE_SECURE_BOOT 16
>+
>+typedef struct {
>+ UINT32 Type;
>+ UINT32 Address;
>+ UINT32 Size;
>+ UINT32 Version; // Used by OptionalModule and PortModule only
>+} FIT_TABLE_CONTEXT_ENTRY;
>+
>+typedef struct {
>+ BOOLEAN Clear;
>+ UINT32 FitTablePointerOffset;
>+ UINT32 FitTablePointerOffset2;
>+ UINT32 FitEntryNumber;
>+ UINT32 BiosModuleNumber;
>+ UINT32 MicrocodeNumber;
>+ UINT32 OptionalModuleNumber;
>+ UINT32 PortModuleNumber;
>+ UINT32 GlobalVersion;
>+ UINT32 FitHeaderVersion;
>+ FIT_TABLE_CONTEXT_ENTRY StartupAcm;
>+ UINT32 StartupAcmVersion;
>+ FIT_TABLE_CONTEXT_ENTRY BiosModule[MAX_BIOS_MODULE_ENTRY];
>+ UINT32 BiosModuleVersion;
>+ FIT_TABLE_CONTEXT_ENTRY Microcode[MAX_MICROCODE_ENTRY];
>+ BOOLEAN MicrocodeAlignment;
>+ UINT32 MicrocodeVersion;
>+ FIT_TABLE_CONTEXT_ENTRY OptionalModule[MAX_OPTIONAL_ENTRY];
>+ FIT_TABLE_CONTEXT_ENTRY PortModule[MAX_PORT_ENTRY];
>+} FIT_TABLE_CONTEXT;
>+
>+FIT_TABLE_CONTEXT gFitTableContext = {0};
>+
>+unsigned int
>+xtoi (
>+ char *str
>+ );
>+
>+VOID
>+PrintUtilityInfo (
>+ VOID
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Displays the standard utility information to STDOUT
>+
>+Arguments:
>+
>+ None
>+
>+Returns:
>+
>+ None
>+
>+--*/
>+{
>+ printf (
>+ "%s - Tiano IA32/X64 FIT table generation Utility."" Version %i.%i\n\n",
>+ UTILITY_NAME,
>+ UTILITY_MAJOR_VERSION,
>+ UTILITY_MINOR_VERSION
>+ );
>+}
>+
>+VOID
>+PrintUsage (
>+ VOID
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Displays the utility usage syntax to STDOUT
>+
>+Arguments:
>+
>+ None
>+
>+Returns:
>+
>+ None
>+
>+--*/
>+{
>+ printf ("Usage (generate): %s [-D] InputFvRecoveryFile
>OutputFvRecoveryFile\n"
>+ "\t[-V <FitEntryDefaultVersion>]\n"
>+ "\t[-F <FitTablePointerOffset>] [-F <FitTablePointerOffset>] [-V
><FitHeaderVersion>]\n"
>+ "\t[-NA]\n"
>+ "\t[-CLEAR]\n"
>+ "\t[-I <BiosInfoGuid>]\n"
>+ "\t[-S <StartupAcmAddress StartupAcmSize>|<StartupAcmGuid>] [-V
><StartupAcmVersion>]\n"
>+ "\t[-B <BiosModuleAddress BiosModuleSize>] [-B ...] [-V
><BiosModuleVersion>]\n"
>+ "\t[-M <MicrocodeAddress MicrocodeSize>] [-M ...]|[-U <MicrocodeFv
>MicrocodeBase>|<MicrocodeRegionOffset
>MicrocodeRegionSize>|<MicrocodeGuid>] [-V <MicrocodeVersion>]\n"
>+ "\t[-O RecordType <RecordDataAddress RecordDataSize>|<RESERVE
>RecordDataSize>|<RecordDataGuid>|<RecordBinFile> [-V <RecordVersion>]]
>[-O ... [-V ...]]\n"
>+ "\t[-P RecordType <IndexPort DataPort Width Bit Index> [-V
><RecordVersion>]] [-P ... [-V ...]]\n"
>+ , UTILITY_NAME);
>+ printf (" Where:\n");
>+ printf ("\t-D - It is FD file instead of FV file. (The tool will search FV
>file)\n");
>+ printf ("\tInputFvRecoveryFile - Name of the input FvRecovery.fv file.\n");
>+ printf ("\tOutputFvRecoveryFile - Name of the output FvRecovery.fv
>file.\n");
>+ printf ("\tFitTablePointerOffset - FIT table pointer offset. 0x%x as default.
>0x18 for current soon to be obsoleted CPUs. User can set both.\n",
>DEFAULT_FIT_TABLE_POINTER_OFFSET);
>+ printf ("\tBiosInfoGuid - Guid of BiosInfo Module. If this module exists,
>StartupAcm/Bios/Microcode can be optional.\n");
>+ printf ("\tStartupAcmAddress - Address of StartupAcm.\n");
>+ printf ("\tStartupAcmSize - Size of StartupAcm.\n");
>+ printf ("\tStartupAcmGuid - Guid of StartupAcm Module, if StartupAcm
>is in a BiosModule, it will be excluded form that.\n");
>+ printf ("\tBiosModuleAddress - Address of BiosModule. User should
>ensure there is no overlap.\n");
>+ printf ("\tBiosModuleSize - Size of BiosModule.\n");
>+ printf ("\tMicrocodeAddress - Address of Microcode.\n");
>+ printf ("\tMicrocodeSize - Size of Microcode.\n");
>+ printf ("\tMicrocodeFv - Name of Microcode.fv file.\n");
>+ printf ("\tMicrocodeBase - The base address of Microcode.fv in final FD
>image.\n");
>+ printf ("\tMicrocodeRegionOffset - Offset of Microcode region in input FD
>image.\n");
>+ printf ("\tMicrocodeRegionSize - Size of Microcode region in input FD
>image.\n");
>+ printf ("\tMicrocodeGuid - Guid of Microcode Module.\n");
>+ printf ("\t-NA - No 0x800 aligned Microcode requirement. No -NA
>means Microcode is 0x800 aligned.\n");
>+ printf ("\tRecordType - FIT entry record type. User should ensure it is
>ordered.\n");
>+ printf ("\tRecordDataAddress - FIT entry record data address.\n");
>+ printf ("\tRecordDataSize - FIT entry record data size.\n");
>+ printf ("\tRecordDataGuid - FIT entry record data GUID.\n");
>+ printf ("\tRecordBinFile - FIT entry record data binary file.\n");
>+ printf ("\tFitEntryDefaultVersion - The default version for all FIT table
>entries. 0x%04x is used if this is not specified.\n",
>DEFAULT_FIT_ENTRY_VERSION);
>+ printf ("\tFitHeaderVersion - The version for FIT header. (Override
>default version)\n");
>+ printf ("\tStartupAcmVersion - The version for StartupAcm. (Override
>default version)\n");
>+ printf ("\tBiosModuleVersion - The version for BiosModule. (Override
>default version)\n");
>+ printf ("\tMicrocodeVersion - The version for Microcode. (Override
>default version)\n");
>+ printf ("\tRecordVersion - The version for Record. (Override default
>version)\n");
>+ printf ("\tIndexPort - The Index Port Number.\n");
>+ printf ("\tDataPort - The Data Port Number.\n");
>+ printf ("\tWidth - The Width of the port.\n");
>+ printf ("\tBit - The Bit Number of the port.\n");
>+ printf ("\tIndex - The Index Number of the port.\n");
>+ printf ("\nUsage (view): %s [-view] InputFile -F <FitTablePointerOffset>\n",
>UTILITY_NAME);
>+ printf (" Where:\n");
>+ printf ("\tInputFile - Name of the input file.\n");
>+ printf ("\tFitTablePointerOffset - FIT table pointer offset from end of file.
>0x%x as default.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
>+ printf ("\nTool return values:\n");
>+ printf ("\tSTATUS_SUCCESS=%d, STATUS_WARNING=%d,
>STATUS_ERROR=%d\n", STATUS_SUCCESS, STATUS_WARNING,
>STATUS_ERROR);
>+}
>+
>+VOID *
>+SetMem (
>+ OUT VOID *Buffer,
>+ IN UINTN Length,
>+ IN UINT8 Value
>+ )
>+{
>+ //
>+ // Declare the local variables that actually move the data elements as
>+ // volatile to prevent the optimizer from replacing this function with
>+ // the intrinsic memset()
>+ //
>+ volatile UINT8 *Pointer;
>+
>+ Pointer = (UINT8*)Buffer;
>+ while (Length-- > 0) {
>+ *(Pointer++) = Value;
>+ }
>+ return Buffer;
>+}
>+
>+STATUS
>+ReadInputFile (
>+ IN CHAR8 *FileName,
>+ OUT UINT8 **FileData,
>+ OUT UINT32 *FileSize,
>+ OUT UINT8 **FileBufferRaw OPTIONAL
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Read input file
>+
>+Arguments:
>+
>+ FileName - The input file name
>+ FileData - The input file data, the memory is aligned.
>+ FileSize - The input file size
>+ FileBufferRaw - The memory to hold input file data. The caller must free the
>memory.
>+
>+Returns:
>+
>+ STATUS_SUCCESS - The file found and data read
>+ STATUS_ERROR - The file data is not read
>+ STATUS_WARNING - The file is not found
>+
>+--*/
>+{
>+ FILE *FpIn;
>+ UINT32 TempResult;
>+
>+ //
>+ // Open the Input FvRecovery.fv file
>+ //
>+ if ((FpIn = fopen (FileName, "rb")) == NULL) {
>+ //
>+ // Return WARNING, let caller make decision
>+ //
>+// Error (NULL, 0, 0, "Unable to open file", FileName);
>+ return STATUS_WARNING;
>+ }
>+ //
>+ // Get the Input FvRecovery.fv file size
>+ //
>+ fseek (FpIn, 0, SEEK_END);
>+ *FileSize = ftell (FpIn);
>+ //
>+ // Read the contents of input file to memory buffer
>+ //
>+ if (FileBufferRaw != NULL) {
>+ *FileBufferRaw = (UINT8 *) malloc (*FileSize + 0x10000);
>+ if (NULL == *FileBufferRaw) {
>+ Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
>+ fclose (FpIn);
>+ return STATUS_ERROR;
>+ }
>+ TempResult = 0x10000 - (UINT32) ((UINTN)*FileBufferRaw & 0x0FFFF);
>+ *FileData = (UINT8 *)((UINTN)*FileBufferRaw + TempResult);
>+ } else {
>+ *FileData = (UINT8 *) malloc (*FileSize);
>+ if (NULL == *FileData) {
>+ Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
>+ fclose (FpIn);
>+ return STATUS_ERROR;
>+ }
>+ }
>+ fseek (FpIn, 0, SEEK_SET);
>+ TempResult = fread (*FileData, 1, *FileSize, FpIn);
>+ if (TempResult != *FileSize) {
>+ Error (NULL, 0, 0, "Read input file error!", NULL);
>+ if (FileBufferRaw != NULL) {
>+ free ((VOID *)*FileBufferRaw);
>+ } else {
>+ free ((VOID *)*FileData);
>+ }
>+ fclose (FpIn);
>+ return STATUS_ERROR;
>+ }
>+
>+ //
>+ // Close the input FvRecovery.fv file
>+ //
>+ fclose (FpIn);
>+
>+ return STATUS_SUCCESS;
>+}
>+
>+UINT8 *
>+FindNextFvHeader (
>+ IN UINT8 *FileBuffer,
>+ IN UINTN FileLength
>+ )
>+/*++
>+
>+ Routine Description:
>+ Find next FvHeader in the FileBuffer
>+
>+ Parameters:
>+ FileBuffer - The start FileBuffer which needs to be searched
>+ FileLength - The whole File Length.
>+ Return:
>+ FvHeader - The FvHeader is found successfully.
>+ NULL - The FvHeader is not found.
>+
>+--*/
>+{
>+ UINT8 *FileHeader;
>+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
>+ UINT16 FileChecksum;
>+
>+ FileHeader = FileBuffer;
>+ for (; (UINTN)FileBuffer < (UINTN)FileHeader + FileLength; FileBuffer += 8) {
>+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer;
>+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+ //
>+ // potential candidate
>+ //
>+
>+ //
>+ // Check checksum
>+ //
>+ if (FvHeader->FvLength > FileLength) {
>+ continue;
>+ }
>+ if (FvHeader->HeaderLength >= FileLength) {
>+ continue;
>+ }
>+ FileChecksum = CalculateChecksum16 ((UINT16 *)FileBuffer, FvHeader-
>>HeaderLength / sizeof (UINT16));
>+ if (FileChecksum != 0) {
>+ continue;
>+ }
>+
>+ //
>+ // Check revision and reserved field
>+ //
>+#if (PI_SPECIFICATION_VERSION < 0x00010000)
>+ if ((FvHeader->Revision == EFI_FVH_REVISION) &&
>+ (FvHeader->Reserved[0] == 0) &&
>+ (FvHeader->Reserved[1] == 0) &&
>+ (FvHeader->Reserved[2] == 0) ){
>+ return FileBuffer;
>+ }
>+#else
>+ if ((FvHeader->Revision == EFI_FVH_PI_REVISION) &&
>+ (FvHeader->Reserved[0] == 0) ){
>+ return FileBuffer;
>+ }
>+#endif
>+ }
>+ }
>+
>+ return NULL;
>+}
>+
>+UINT8 *
>+FindFileFromFvByGuid (
>+ IN UINT8 *FvBuffer,
>+ IN UINT32 FvSize,
>+ IN EFI_GUID *Guid,
>+ OUT UINT32 *FileSize
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Find File with GUID in an FV
>+
>+Arguments:
>+
>+ FvBuffer - FV binary buffer
>+ FvSize - FV size
>+ Guid - File GUID value to be searched
>+ FileSize - Guid File size
>+
>+Returns:
>+
>+ FileLocation - Guid File location.
>+ NULL - Guid File is not found.
>+
>+--*/
>+{
>+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
>+ EFI_FFS_FILE_HEADER *FileHeader;
>+ UINT64 FvLength;
>+ EFI_GUID *TempGuid;
>+ UINT8 *FixPoint;
>+ UINT32 Offset;
>+ UINT32 FileLength;
>+ UINT32 FileOccupiedSize;
>+
>+ //
>+ // Find the FFS file
>+ //
>+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader
>(FvBuffer, FvSize);
>+ if (NULL == FvHeader) {
>+ return NULL;
>+ }
>+ while (TRUE) {
>+ FvLength = FvHeader->FvLength;
>+
>+ //
>+ // Prepare to walk the FV image
>+ //
>+ InitializeFvLib (FvHeader, (UINT32)FvLength);
>+
>+ FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + FvHeader-
>>HeaderLength);
>+ Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
>+
>+ while (Offset < FvLength) {
>+ TempGuid = (EFI_GUID *)&(FileHeader->Name);
>+ FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
>+ FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
>+ if ((CompareGuid (TempGuid, Guid)) == 0) {
>+ //
>+ // Good! Find it.
>+ //
>+ FixPoint = ((UINT8 *)FileHeader + sizeof(EFI_FFS_FILE_HEADER));
>+ //
>+ // Find the position of file module, the offset
>+ // between the position and the end of FvRecovery.fv file
>+ // should not exceed 128kB to prevent reset vector from
>+ // outside legacy E and F segment
>+ //
>+ if ((UINTN)FvHeader + FvLength - (UINTN)FixPoint > 0x20000) {
>+ // printf ("WARNING: The position of file module is not in E and F
>segment!\n");
>+ // return NULL;
>+ }
>+ *FileSize = FileLength - sizeof(EFI_FFS_FILE_HEADER);
>+ #if (PI_SPECIFICATION_VERSION < 0x00010000)
>+ if (FileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
>+ *FileSize -= sizeof(EFI_FFS_FILE_TAIL);
>+ }
>+ #endif
>+ return FixPoint;
>+ }
>+ FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader +
>FileOccupiedSize);
>+ Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
>+ }
>+
>+ //
>+ // Not found, check next FV
>+ //
>+ if ((UINTN)FvBuffer + FvSize > (UINTN)FvHeader + FvLength) {
>+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader
>((UINT8 *)FvHeader + (UINTN)FvLength, (UINTN)FvBuffer + FvSize -
>((UINTN)FvHeader + (UINTN)FvLength));
>+ if (FvHeader == NULL) {
>+ break;
>+ }
>+ } else {
>+ break;
>+ }
>+ }
>+
>+ //
>+ // Not found
>+ //
>+ return NULL;
>+}
>+
>+BOOLEAN
>+IsGuidData (
>+ IN CHAR8 *StringData,
>+ OUT EFI_GUID *Guid
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Check whether a string is a GUID
>+
>+Arguments:
>+
>+ StringData - the String
>+ Guid - Guid to hold the value
>+
>+Returns:
>+
>+ TRUE - StringData is a GUID, and Guid field is filled.
>+ FALSE - StringData is not a GUID
>+
>+--*/
>+{
>+ if (strlen (StringData) != strlen ("00000000-0000-0000-0000-000000000000"))
>{
>+ return FALSE;
>+ }
>+ if ((StringData[8] != '-') ||
>+ (StringData[13] != '-') ||
>+ (StringData[18] != '-') ||
>+ (StringData[23] != '-') ) {
>+ return FALSE;
>+ }
>+
>+ StringToGuid (StringData, Guid);
>+
>+ return TRUE;
>+}
>+
>+VOID
>+CheckOverlap (
>+ IN UINT32 Address,
>+ IN UINT32 Size
>+ )
>+{
>+ INTN Index;
>+
>+ for (Index = 0; Index < (INTN)gFitTableContext.BiosModuleNumber; Index
>++) {
>+ if ((gFitTableContext.BiosModule[Index].Address <= Address) &&
>+ ((gFitTableContext.BiosModule[Index].Size - Size) >= (Address -
>gFitTableContext.BiosModule[Index].Address))) {
>+ UINT32 TempSize;
>+ INT32 SubIndex;
>+
>+ //
>+ // Found overlap, split BiosModuleEntry
>+ // Currently only support StartupAcm in 1 BiosModule. It does not
>support StartupAcm across 2 BiosModule or more.
>+ //
>+ if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY)
>{
>+ Error (NULL, 0, 0, "Too many Bios Module!", NULL);
>+ return ;
>+ }
>+
>+ if (Address != gFitTableContext.BiosModule[Index].Address) {
>+ //
>+ // Skip the entry whose start address is same as StartupAcm
>+ //
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type
>= FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = gFitTableContext.BiosModule[Index].Address;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size =
>Address - gFitTableContext.BiosModule[Index].Address;
>+ gFitTableContext.BiosModuleNumber ++;
>+ gFitTableContext.FitEntryNumber++;
>+ }
>+
>+ TempSize = gFitTableContext.BiosModule[Index].Address +
>gFitTableContext.BiosModule[Index].Size;
>+ gFitTableContext.BiosModule[Index].Address = Address + Size;
>+ gFitTableContext.BiosModule[Index].Size = TempSize -
>gFitTableContext.BiosModule[Index].Address;
>+
>+ if (gFitTableContext.BiosModule[Index].Size == 0) {
>+ //
>+ // remove the entry if size is 0
>+ //
>+ for (SubIndex = Index; SubIndex <
>(INTN)gFitTableContext.BiosModuleNumber - 1; SubIndex ++) {
>+ gFitTableContext.BiosModule[SubIndex].Address =
>gFitTableContext.BiosModule[SubIndex + 1].Address;
>+ gFitTableContext.BiosModule[SubIndex].Size =
>gFitTableContext.BiosModule[SubIndex + 1].Size;
>+ }
>+ gFitTableContext.BiosModuleNumber --;
>+ gFitTableContext.FitEntryNumber--;
>+ }
>+ break;
>+ }
>+ }
>+}
>+
>+UINT32
>+GetFitEntryNumber (
>+ IN INTN argc,
>+ IN CHAR8 **argv,
>+ IN UINT8 *FdBuffer,
>+ IN UINT32 FdSize
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Get FIT entry number and fill global FIT table context, from argument
>+
>+Arguments:
>+
>+ argc - Number of command line parameters.
>+ argv - Array of pointers to parameter strings.
>+ FdBuffer - FD binary buffer
>+ FdSize - FD size
>+
>+Returns:
>+
>+ FitEntryNumber - The FIT entry number
>+ 0 - Argument parse fail
>+
>+*/
>+{
>+ EFI_GUID Guid;
>+ INTN Index;
>+ UINT8 *FileBuffer;
>+ UINT32 FileSize;
>+ UINT32 Type;
>+ UINT8 *MicrocodeFileBuffer;
>+ UINT8 *MicrocodeFileBufferRaw;
>+ UINT32 MicrocodeFileSize;
>+ UINT32 MicrocodeBase;
>+ UINT32 MicrocodeSize;
>+ UINT8 *MicrocodeBuffer;
>+ UINT32 MicrocodeRegionOffset;
>+ UINT32 MicrocodeRegionSize;
>+ STATUS Status;
>+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
>+ UINTN FitEntryNumber;
>+ BOOLEAN BiosInfoExist;
>+ BIOS_INFO_HEADER *BiosInfo;
>+ BIOS_INFO_STRUCT *BiosInfoStruct;
>+ UINTN BiosInfoIndex;
>+
>+ //
>+ // Init index
>+ //
>+ Index = 3;
>+ if (((strcmp (argv[1], "-D") == 0) ||
>+ (strcmp (argv[1], "-d") == 0)) ) {
>+ Index ++;
>+ }
>+
>+ //
>+ // Fill Global Version
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-V") != 0) &&
>+ (strcmp (argv[Index], "-v") != 0)) ) {
>+ gFitTableContext.GlobalVersion = DEFAULT_FIT_ENTRY_VERSION;
>+ } else {
>+ gFitTableContext.GlobalVersion = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+
>+ //
>+ // 0. FIT Header
>+ //
>+ gFitTableContext.FitEntryNumber = 1;
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-F") != 0) &&
>+ (strcmp (argv[Index], "-f") != 0)) ) {
>+ //
>+ // Use default address
>+ //
>+ gFitTableContext.FitTablePointerOffset =
>DEFAULT_FIT_TABLE_POINTER_OFFSET;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+ gFitTableContext.FitTablePointerOffset = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+
>+ //
>+ // 0.1 FIT Header 2
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-F") != 0) &&
>+ (strcmp (argv[Index], "-f") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+ gFitTableContext.FitTablePointerOffset2 = 0;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+ gFitTableContext.FitTablePointerOffset2 = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+
>+ //
>+ // 0.2 FIT Header version
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-V") != 0) &&
>+ (strcmp (argv[Index], "-v") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+ gFitTableContext.FitHeaderVersion = gFitTableContext.GlobalVersion;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+ gFitTableContext.FitHeaderVersion = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+
>+ //
>+ // 0.3 Microcode alignment
>+ //
>+ if ((Index >= argc) ||
>+ ((strcmp (argv[Index], "-NA") != 0) &&
>+ (strcmp (argv[Index], "-na") != 0)) ) {
>+ //
>+ // by pass
>+ //
>+ gFitTableContext.MicrocodeAlignment = TRUE;
>+ } else {
>+ //
>+ // no alignment
>+ //
>+ gFitTableContext.MicrocodeAlignment = FALSE;
>+ Index += 1;
>+ }
>+
>+ //
>+ // 0.4 Clear FIT table related memory
>+ //
>+ if ((Index >= argc) ||
>+ ((strcmp (argv[Index], "-CLEAR") != 0) &&
>+ (strcmp (argv[Index], "-clear") != 0)) ) {
>+ //
>+ // by pass
>+ //
>+ gFitTableContext.Clear = FALSE;
>+ } else {
>+ //
>+ // Clear FIT table
>+ //
>+ gFitTableContext.Clear = TRUE;
>+ //
>+ // Do not parse any more
>+ //
>+ return 0;
>+ }
>+
>+ //
>+ // 0.5 BiosInfo
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-I") != 0) &&
>+ (strcmp (argv[Index], "-i") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+ BiosInfoExist = FALSE;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+ BiosInfoExist = TRUE;
>+ if (IsGuidData (argv[Index + 1], &Guid)) {
>+ FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
>+ if (FileBuffer == NULL) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, GUID not found!", "%s",
>argv[Index + 1]);
>+ // not found
>+ return 0;
>+ }
>+ BiosInfo = (BIOS_INFO_HEADER *)FileBuffer;
>+ for (BiosInfoIndex = 0; BiosInfoIndex < FileSize; BiosInfoIndex++) {
>+ if (((BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex))->Signature ==
>BIOS_INFO_SIGNATURE) {
>+ BiosInfo = (BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex);
>+ }
>+ }
>+ if (BiosInfo->Signature != BIOS_INFO_SIGNATURE) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, Signature Error!", NULL);
>+ // not found
>+ return 0;
>+ }
>+ BiosInfoStruct = (BIOS_INFO_STRUCT *)(BiosInfo + 1);
>+
>+ for (BiosInfoIndex = 0; BiosInfoIndex < BiosInfo->EntryCount;
>BiosInfoIndex++) {
>+ if ((BiosInfoStruct[BiosInfoIndex].Attributes &
>BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT) != 0) {
>+ continue;
>+ }
>+ switch (BiosInfoStruct[BiosInfoIndex].Type) {
>+ case FIT_TABLE_TYPE_HEADER:
>+ Error (NULL, 0, 0, "-I Parameter incorrect, Header Type unsupported!",
>NULL);
>+ return 0;
>+ case FIT_TABLE_TYPE_STARTUP_ACM:
>+ if (gFitTableContext.StartupAcm.Type != 0) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, Duplicated StartupAcm!",
>NULL);
>+ return 0;
>+ }
>+ gFitTableContext.StartupAcm.Type =
>FIT_TABLE_TYPE_STARTUP_ACM;
>+ gFitTableContext.StartupAcm.Address =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+ gFitTableContext.StartupAcm.Size =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+ gFitTableContext.StartupAcmVersion =
>BiosInfoStruct[BiosInfoIndex].Version;
>+ gFitTableContext.FitEntryNumber ++;
>+ break;
>+ case FIT_TABLE_TYPE_BIOS_MODULE:
>+ if ((BiosInfoStruct[BiosInfoIndex].Attributes &
>BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB) != 0) {
>+ continue;
>+ }
>+ if (gFitTableContext.BiosModuleNumber >=
>MAX_BIOS_MODULE_ENTRY) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Bios Module!",
>NULL);
>+ return 0;
>+ }
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type
>= FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+ gFitTableContext.BiosModuleVersion =
>BiosInfoStruct[BiosInfoIndex].Version;
>+ gFitTableContext.BiosModuleNumber ++;
>+ gFitTableContext.FitEntryNumber ++;
>+ break;
>+ case FIT_TABLE_TYPE_MICROCODE:
>+ if ((BiosInfoStruct[BiosInfoIndex].Attributes &
>BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION) == 0) {
>+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY)
>{
>+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Microcode!",
>NULL);
>+ return 0;
>+ }
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type =
>FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+ gFitTableContext.MicrocodeVersion =
>BiosInfoStruct[BiosInfoIndex].Version;
>+ gFitTableContext.MicrocodeNumber++;
>+ gFitTableContext.FitEntryNumber++;
>+ } else {
>+ MicrocodeRegionOffset =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+ MicrocodeRegionSize = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+ if (MicrocodeRegionOffset == 0) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionOffset is 0",
>NULL);
>+ return 0;
>+ }
>+ if (MicrocodeRegionSize == 0) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize is 0",
>NULL);
>+ return 0;
>+ }
>+ if (MicrocodeRegionSize > FdSize) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize too
>large", NULL);
>+ return 0;
>+ }
>+
>+ MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset,
>FdBuffer, FdSize);
>+ MicrocodeFileSize = MicrocodeRegionSize;
>+ MicrocodeBase = MicrocodeRegionOffset;
>+
>+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER
>*)MicrocodeFileBuffer;
>+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+ // Skip FV header + FFS header
>+ MicrocodeBuffer = MicrocodeFileBuffer +
>sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
>sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
>+ } else {
>+ MicrocodeBuffer = MicrocodeFileBuffer;
>+ }
>+ while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) <
>MicrocodeFileSize) {
>+ if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
>+ break;
>+ }
>+ if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
>+ break;
>+ }
>+ if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
>+ MicrocodeSize = 2048;
>+ } else {
>+ //
>+ // MCU might be put at 2KB alignment, if so, we need to adjust the
>size as 2KB alignment.
>+ //
>+ if (gFitTableContext.MicrocodeAlignment) {
>+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) +
>MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
>+ } else {
>+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
>+ }
>+ }
>+
>+ //
>+ // Add Microcode
>+ //
>+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY)
>{
>+ printf ("-I Parameter incorrect, Too many Microcode!\n");
>+ return 0;
>+ }
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type =
>FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN)
>MicrocodeFileBuffer);
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size =
>MicrocodeSize;
>+ gFitTableContext.MicrocodeNumber++;
>+ gFitTableContext.FitEntryNumber++;
>+
>+ MicrocodeBuffer += MicrocodeSize;
>+ }
>+ }
>+ break;
>+ case FIT_TABLE_TYPE_TPM_POLICY:
>+ case FIT_TABLE_TYPE_BIOS_POLICY:
>+ case FIT_TABLE_TYPE_TXT_POLICY:
>+ case FIT_TABLE_TYPE_KEY_MANIFEST:
>+ case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
>+ case FIT_TABLE_TYPE_BIOS_DATA_AREA:
>+ case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
>+ default :
>+ if (BiosInfoStruct[BiosInfoIndex].Version != 0) {
>+ if (gFitTableContext.OptionalModuleNumber >=
>MAX_OPTIONAL_ENTRY) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Optional
>Module!", NULL);
>+ return 0;
>+ }
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Type = BiosInfoStruct[BiosInfoIndex].Type;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = BiosInfoStruct[BiosInfoIndex].Version;
>+ gFitTableContext.OptionalModuleNumber++;
>+ gFitTableContext.FitEntryNumber++;
>+ } else {
>+ if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, Too many Port Module!",
>NULL);
>+ return 0;
>+ }
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type
>= BiosInfoStruct[BiosInfoIndex].Type;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Addres
>s = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size =
>(UINT32)(BiosInfoStruct[BiosInfoIndex].Address >> 32);
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= BiosInfoStruct[BiosInfoIndex].Version;
>+ gFitTableContext.PortModuleNumber++;
>+ gFitTableContext.FitEntryNumber++;
>+ }
>+ break;
>+ }
>+ }
>+
>+ } else {
>+ Error (NULL, 0, 0, "-I Parameter incorrect, expect GUID!", NULL);
>+ return 0;
>+ }
>+ Index += 2;
>+ }
>+
>+ //
>+ // 1. StartupAcm
>+ //
>+ do {
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-S") != 0) &&
>+ (strcmp (argv[Index], "-s") != 0)) ) {
>+ if (BiosInfoExist && (gFitTableContext.StartupAcm.Type ==
>FIT_TABLE_TYPE_STARTUP_ACM)) {
>+ break;
>+ }
>+// Error (NULL, 0, 0, "-S Parameter incorrect, expect -S!", NULL);
>+// return 0;
>+ printf ("-S not found. WARNING!\n");
>+ break;
>+ }
>+ if (IsGuidData (argv[Index + 1], &Guid)) {
>+ FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
>+ if (FileBuffer == NULL) {
>+ Error (NULL, 0, 0, "-S Parameter incorrect, GUID not found!", "%s",
>argv[Index + 1]);
>+ // not found
>+ return 0;
>+ }
>+ FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
>+ Index += 2;
>+ } else {
>+ if (Index + 2 >= argc) {
>+ Error (NULL, 0, 0, "-S Parameter incorrect, expect Address Size!", NULL);
>+ return 0;
>+ }
>+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+ FileSize = xtoi (argv[Index + 2]);
>+ Index += 3;
>+ }
>+ if (gFitTableContext.StartupAcm.Type != 0) {
>+ Error (NULL, 0, 0, "-S Parameter incorrect, Duplicated StartupAcm!", NULL);
>+ return 0;
>+ }
>+ gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM;
>+ gFitTableContext.StartupAcm.Address = (UINT32) (UINTN) FileBuffer;
>+ gFitTableContext.StartupAcm.Size = FileSize;
>+ gFitTableContext.FitEntryNumber ++;
>+
>+ //
>+ // 1.1 StartupAcm version
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-V") != 0) &&
>+ (strcmp (argv[Index], "-v") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+ gFitTableContext.StartupAcmVersion = gFitTableContext.GlobalVersion;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+ gFitTableContext.StartupAcmVersion = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+ } while (FALSE);
>+
>+ //
>+ // 2. BiosModule
>+ //
>+ do {
>+ if ((Index + 2 >= argc) ||
>+ ((strcmp (argv[Index], "-B") != 0) &&
>+ (strcmp (argv[Index], "-b") != 0)) ) {
>+ if (BiosInfoExist && (gFitTableContext.BiosModuleNumber != 0)) {
>+ break;
>+ }
>+// Error (NULL, 0, 0, "-B Parameter incorrect, expect -B!", NULL);
>+// return 0;
>+ printf ("-B not found. WARNING!\n");
>+ break;
>+ }
>+
>+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+ FileSize = xtoi (argv[Index + 2]);
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type =
>FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32) (UINTN) FileBuffer;
>+ gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size
>= FileSize;
>+ gFitTableContext.BiosModuleNumber ++;
>+ gFitTableContext.FitEntryNumber ++;
>+
>+ while (TRUE) {
>+ Index += 3;
>+ if (Index + 2 >= argc) {
>+ break;
>+ }
>+ if ((strcmp (argv[Index], "-B") != 0) &&
>+ (strcmp (argv[Index], "-b") != 0) ) {
>+ break;
>+ }
>+ if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY)
>{
>+ Error (NULL, 0, 0, "-B Parameter incorrect, Too many Bios Module!",
>NULL);
>+ return 0;
>+ }
>+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+ FileSize = xtoi (argv[Index + 2]);
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type =
>FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32) (UINTN) FileBuffer;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size =
>FileSize;
>+ gFitTableContext.BiosModuleNumber ++;
>+ gFitTableContext.FitEntryNumber++;
>+ }
>+
>+ //
>+ // 2.1 BiosModule version
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-V") != 0) &&
>+ (strcmp (argv[Index], "-v") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+ gFitTableContext.BiosModuleVersion = gFitTableContext.GlobalVersion;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+ gFitTableContext.BiosModuleVersion = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+ } while (FALSE);
>+
>+ //
>+ // 3. Microcode
>+ //
>+ while (TRUE) {
>+ if (Index + 1 >= argc) {
>+ break;
>+ }
>+ if ((strcmp (argv[Index], "-M") != 0) &&
>+ (strcmp (argv[Index], "-m") != 0) ) {
>+ break;
>+ }
>+ if (IsGuidData (argv[Index + 2], &Guid)) {
>+ Error (NULL, 0, 0, "-M Parameter incorrect, GUID unsupported!", NULL);
>+ return 0;
>+ } else {
>+ if (Index + 2 >= argc) {
>+ break;
>+ }
>+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+ FileSize = xtoi (argv[Index + 2]);
>+ Index += 3;
>+ }
>+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
>+ Error (NULL, 0, 0, "-M Parameter incorrect, Too many Microcode!", NULL);
>+ return 0;
>+ }
>+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type =
>FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>(UINT32) (UINTN) FileBuffer;
>+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size =
>FileSize;
>+ gFitTableContext.MicrocodeNumber++;
>+ gFitTableContext.FitEntryNumber++;
>+ }
>+
>+ //
>+ // 3.1 MicrocodeFv
>+ //
>+ while (TRUE) {
>+ if (Index + 1 >= argc) {
>+ break;
>+ }
>+ if ((strcmp (argv[Index], "-U") != 0) &&
>+ (strcmp (argv[Index], "-u") != 0) ) {
>+ break;
>+ }
>+ //
>+ // Get Fv
>+ //
>+ if (IsGuidData (argv[Index + 1], &Guid)) {
>+ MicrocodeFileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid,
>&MicrocodeFileSize);
>+ if (MicrocodeFileBuffer == NULL) {
>+ Error (NULL, 0, 0, "-U Parameter incorrect, GUID not found!", "%s",
>argv[Index + 1]);
>+ // not found
>+ return 0;
>+ }
>+ Index += 2;
>+
>+ MicrocodeBuffer = MicrocodeFileBuffer;
>+ MicrocodeFileBufferRaw = NULL;
>+ MicrocodeRegionOffset = MEMORY_TO_FLASH (MicrocodeFileBuffer,
>FdBuffer, FdSize);
>+ MicrocodeRegionSize = 0;
>+ MicrocodeBase = MicrocodeRegionOffset;
>+
>+ } else {
>+ if (Index + 2 >= argc) {
>+ break;
>+ }
>+ Status = ReadInputFile (argv[Index + 1], &MicrocodeFileBuffer,
>&MicrocodeFileSize, &MicrocodeFileBufferRaw);
>+ if (Status != STATUS_SUCCESS) {
>+ MicrocodeRegionOffset = xtoi (argv[Index + 1]);
>+ MicrocodeRegionSize = xtoi (argv[Index + 2]);
>+
>+ if (MicrocodeRegionOffset == 0) {
>+ Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionOffset is 0,
>or unable to open file", "%s", argv[Index + 1]);
>+ return 0;
>+ }
>+ if (MicrocodeRegionSize == 0) {
>+ Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize is 0",
>NULL);
>+ return 0;
>+ }
>+ if (MicrocodeRegionSize > FdSize) {
>+ Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize too
>large", NULL);
>+ return 0;
>+ }
>+
>+ Index += 3;
>+
>+ MicrocodeFileBufferRaw = NULL;
>+ MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset,
>FdBuffer, FdSize);
>+ MicrocodeFileSize = MicrocodeRegionSize;
>+ MicrocodeBase = MicrocodeRegionOffset;
>+
>+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
>+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+ // Skip FV header + FFS header
>+ MicrocodeBuffer = MicrocodeFileBuffer +
>sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
>sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
>+ } else {
>+ MicrocodeBuffer = MicrocodeFileBuffer;
>+ }
>+ } else {
>+ MicrocodeBase = xtoi (argv[Index + 2]);
>+ Index += 3;
>+ MicrocodeRegionOffset = 0;
>+ MicrocodeRegionSize = 0;
>+
>+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
>+ if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+ // Skip FV header + FFS header
>+ MicrocodeBuffer = MicrocodeFileBuffer +
>sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
>sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
>+ } else {
>+ MicrocodeBuffer = MicrocodeFileBuffer;
>+ }
>+ }
>+ }
>+ while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) <
>MicrocodeFileSize) {
>+ if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
>+ break;
>+ }
>+ if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
>+ break;
>+ }
>+ if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
>+ MicrocodeSize = 2048;
>+ } else {
>+ //
>+ // MCU might be put at 2KB alignment, if so, we need to adjust the size
>as 2KB alignment.
>+ //
>+ if (gFitTableContext.MicrocodeAlignment) {
>+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) +
>MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
>+ } else {
>+ MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
>+ }
>+ }
>+
>+ //
>+ // Add Microcode
>+ //
>+ if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
>+ printf ("-U Parameter incorrect, Too many Microcode!\n");
>+ return 0;
>+ }
>+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type
>= FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN)
>MicrocodeFileBuffer);
>+ gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size =
>MicrocodeSize;
>+ gFitTableContext.MicrocodeNumber++;
>+ gFitTableContext.FitEntryNumber++;
>+
>+ MicrocodeBuffer += MicrocodeSize;
>+ }
>+
>+ if (MicrocodeFileBufferRaw != NULL) {
>+ free ((VOID *)MicrocodeFileBufferRaw);
>+ MicrocodeFileBufferRaw = NULL;
>+ }
>+ }
>+
>+ //
>+ // 3.3 Microcode version
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-V") != 0) &&
>+ (strcmp (argv[Index], "-v") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+ gFitTableContext.MicrocodeVersion = gFitTableContext.GlobalVersion;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+ gFitTableContext.MicrocodeVersion = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+
>+ //
>+ // 4. Optional type
>+ //
>+ while (TRUE) {
>+ if (Index + 2 >= argc) {
>+ break;
>+ }
>+ if ((strcmp (argv[Index], "-O") != 0) &&
>+ (strcmp (argv[Index], "-o") != 0) ) {
>+ break;
>+ }
>+ Type = xtoi (argv[Index + 1]);
>+ //
>+ // 1st, try GUID
>+ //
>+ if (IsGuidData (argv[Index + 2], &Guid)) {
>+ FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
>+ if (FileBuffer == NULL) {
>+ Error (NULL, 0, 0, "-O Parameter incorrect, GUID not found!", "%s",
>argv[Index + 2]);
>+ // not found
>+ return 0;
>+ }
>+ if (FileSize >= 0x80000000) {
>+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+ return 0;
>+ }
>+ FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
>+ Index += 3;
>+ } else {
>+ //
>+ // 2nd, try file
>+ //
>+ Status = ReadInputFile (argv[Index + 2], &FileBuffer, &FileSize, NULL);
>+ if (Status == STATUS_SUCCESS) {
>+ if (FileSize >= 0x80000000) {
>+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+ free (FileBuffer);
>+ return 0;
>+ }
>+ //
>+ // Set the most significant bit
>+ // It means the data in memory, not in flash yet.
>+ // Assume the file size should < 2G.
>+ //
>+ FileSize |= 0x80000000;
>+ Index += 3;
>+ } else {
>+ //
>+ // 3rd, try <RESERVE, Length>
>+ //
>+ if (Index + 3 >= argc) {
>+ break;
>+ }
>+ if ((strcmp (argv[Index + 2], "RESERVE") == 0) ||
>+ (strcmp (argv[Index + 2], "reserve") == 0)) {
>+ FileSize = xtoi (argv[Index + 3]);
>+ if (FileSize >= 0x80000000) {
>+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+ return 0;
>+ }
>+ FileBuffer = malloc (FileSize);
>+ if (FileBuffer == NULL) {
>+ Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
>+ return 0;
>+ }
>+ SetMem (FileBuffer, FileSize, 0xFF);
>+ //
>+ // Set the most significant bit
>+ // It means the data in memory, not in flash yet.
>+ // Assume the file size should < 2G.
>+ //
>+ FileSize |= 0x80000000;
>+ Index += 4;
>+ } else {
>+ //
>+ // 4th, try <Address, Length>
>+ //
>+ if (Index + 3 >= argc) {
>+ break;
>+ }
>+ FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 2]);
>+ FileSize = xtoi (argv[Index + 3]);
>+ if (FileSize >= 0x80000000) {
>+ Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+ return 0;
>+ }
>+ Index += 4;
>+ }
>+ }
>+ }
>+ if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY)
>{
>+ Error (NULL, 0, 0, "-O Parameter incorrect, Too many Optional Module!",
>NULL);
>+ free (FileBuffer);
>+ return 0;
>+ }
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Type = Type;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Address = (UINT32) (UINTN) FileBuffer;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Size = FileSize;
>+
>+ //
>+ // 4.1 Optional Module version
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-V") != 0) &&
>+ (strcmp (argv[Index], "-v") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = gFitTableContext.GlobalVersion;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+
>+ gFitTableContext.OptionalModuleNumber ++;
>+ gFitTableContext.FitEntryNumber++;
>+ }
>+
>+ //
>+ // 5. Port type
>+ //
>+ while (TRUE) {
>+ if (Index + 6 >= argc) {
>+ break;
>+ }
>+ if ((strcmp (argv[Index], "-P") != 0) &&
>+ (strcmp (argv[Index], "-p") != 0) ) {
>+ break;
>+ }
>+
>+ Type = xtoi (argv[Index + 1]);
>+ if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
>+ printf ("-P Parameter incorrect, Too many Port Module!\n");
>+ return 0;
>+ }
>+
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type =
>Type;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Addres
>s = (UINT16)xtoi (argv[Index + 2]) + ((UINT16)xtoi (argv[Index + 3]) << 16);
>+ gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size
>= (UINT8)xtoi (argv[Index + 4]) + ((UINT8)xtoi (argv[Index + 5]) << 8) +
>((UINT16)xtoi (argv[Index + 6]) << 16);
>+ Index += 7;
>+
>+ //
>+ // 5.1 Port Module version
>+ //
>+ if ((Index + 1 >= argc) ||
>+ ((strcmp (argv[Index], "-V") != 0) &&
>+ (strcmp (argv[Index], "-v") != 0)) ) {
>+ //
>+ // Bypass
>+ //
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= 0;
>+ } else {
>+ //
>+ // Get offset from parameter
>+ //
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= xtoi (argv[Index + 1]);
>+ Index += 2;
>+ }
>+
>+ gFitTableContext.PortModuleNumber++;
>+ gFitTableContext.FitEntryNumber++;
>+ }
>+
>+ //
>+ // Final: Check StartupAcm in BiosModule.
>+ //
>+ CheckOverlap (gFitTableContext.StartupAcm.Address,
>gFitTableContext.StartupAcm.Size);
>+ FitEntryNumber = gFitTableContext.FitEntryNumber;
>+ for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber;
>Index++) {
>+ if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+ // NOTE: It might be virtual address now. Just put a place holder.
>+ FitEntryNumber ++;
>+ }
>+ }
>+
>+ return FitEntryNumber;
>+}
>+
>+VOID *
>+FindSpaceSkipApVector (
>+ IN UINT8 *FvBuffer,
>+ IN UINT8 *Address,
>+ IN UINTN Size
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ No enough space - it might happen that it is occupied by AP wake vector.
>+ Last chance - skip this and search again.
>+
>+Arguments:
>+
>+ FvBuffer - FvRecovery binary buffer
>+ Address - Address to be searched from
>+ Size - Size need to be filled
>+
>+Returns:
>+
>+ FitTableOffset - The FIT table offset
>+ NULL - No enough space for FIT table
>+
>+*/
>+{
>+ UINT8 *ApVector;
>+ UINT8 *NewAddress;
>+ UINTN Index;
>+
>+ ApVector = (UINT8 *)((UINTN)Address & ~0xFFF);
>+ if ((UINTN)ApVector <= (UINTN)FvBuffer) {
>+ return NULL;
>+ }
>+
>+ NewAddress = (UINT8 *)(ApVector - Size);
>+ for (Index = 0; Index < Size; Index ++) {
>+ if (NewAddress[Index] != 0xFF) {
>+ return NULL;
>+ }
>+ }
>+ return NewAddress;
>+}
>+
>+VOID *
>+GetFreeSpaceFromFv (
>+ IN UINT8 *FvBuffer,
>+ IN UINT32 FvSize,
>+ IN UINT32 FitEntryNumber
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Get free space for FIT table from FvRecovery
>+
>+Arguments:
>+
>+ FvBuffer - FvRecovery binary buffer
>+ FvSize - FvRecovery size
>+ FitEntryNumber - The FIT entry number
>+
>+Returns:
>+
>+ FitTableOffset - The offset of FIT table in FvRecovery file
>+ NULL - Free space not found
>+
>+--*/
>+{
>+ UINT8 *FitTableOffset;
>+ INTN Index;
>+ INTN SubIndex;
>+ UINT8 *OptionalModuleAddress;
>+ EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
>+ UINT32 AlignedSize;
>+ UINT32 FitTableSize;
>+
>+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
>+ EFI_FFS_FILE_HEADER *FileHeader;
>+ UINT64 FvLength;
>+ UINT32 Offset;
>+ UINT32 FileLength;
>+ UINT32 FileOccupiedSize;
>+
>+ //
>+ // Check 4G - FitTablePointerOffset
>+ //
>+ if ((*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset) != 0xFFFFFFFFFFFFFFFFull) &&
>+ (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset) != 0) &&
>+ (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset) != 0xEEEEEEEEEEEEEEEEull)) {
>+ Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
>+ return NULL;
>+ }
>+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+ if ((*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset2) != 0xFFFFFFFFFFFFFFFFull) &&
>+ (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset2) != 0) &&
>+ (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset2) != 0xEEEEEEEEEEEEEEEEull)) {
>+ Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
>+ return NULL;
>+ }
>+ }
>+
>+ //
>+ // Get EFI_FFS_VOLUME_TOP_FILE_GUID location
>+ //
>+ FitTableOffset = NULL;
>+
>+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvBuffer;
>+ FvLength = FvHeader->FvLength;
>+ FileHeader = (EFI_FFS_FILE_HEADER *)(FvBuffer + FvHeader-
>>HeaderLength);
>+ Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
>+
>+ while (Offset < FvLength) {
>+ FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
>+ FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
>+ if ((CompareGuid (&(FileHeader->Name), &VTFGuid)) == 0) {
>+ // find it
>+ FitTableOffset = (UINT8 *)FileHeader;
>+ break;
>+ }
>+ FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader +
>FileOccupiedSize);
>+ Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
>+ }
>+
>+ if (FitTableOffset == NULL) {
>+ Error (NULL, 0, 0, "EFI_FFS_VOLUME_TOP_FILE_GUID not found!", NULL);
>+ return NULL;
>+ }
>+
>+ FitTableSize = FitEntryNumber *
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
>+ FitTableSize += FIT_ALIGNMENT;
>+ FitTableSize &= ~FIT_ALIGNMENT;
>+
>+ FitTableOffset = (UINT8 *)((UINTN)FitTableOffset & ~FIT_ALIGNMENT);
>+ FitTableOffset = (UINT8 *)(FitTableOffset - FitTableSize);
>+
>+ //
>+ // Check it
>+ //
>+ for (Index = 0; Index < (INTN)(FitTableSize); Index ++) {
>+ if (FitTableOffset[Index] != 0xFF) {
>+ //
>+ // No enough space - it might happen that it is occupied by AP wake
>vector.
>+ // Last chance - skip this and search again.
>+ //
>+ FitTableOffset = FindSpaceSkipApVector (FvBuffer,
>&FitTableOffset[Index], FitTableSize);
>+ if (FitTableOffset == NULL) {
>+ Error (NULL, 0, 0, "No enough space for FIT table!", NULL);
>+ return NULL;
>+ }
>+ }
>+ }
>+
>+ //
>+ // Check space for Optional module
>+ //
>+ OptionalModuleAddress = FitTableOffset;
>+ for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber;
>Index++) {
>+ AlignedSize = gFitTableContext.OptionalModule[Index].Size;
>+ if ((gFitTableContext.OptionalModule[Index].Size & 0x80000000) != 0) {
>+
>+ //
>+ // Need copy binary to file.
>+ //
>+ gFitTableContext.OptionalModule[Index].Size &= ~0x80000000;
>+
>+ AlignedSize = gFitTableContext.OptionalModule[Index].Size;
>+ if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+ // Let it 64 byte align
>+ AlignedSize += BIOS_MODULE_ALIGNMENT;
>+ AlignedSize &= ~BIOS_MODULE_ALIGNMENT;
>+ }
>+
>+ OptionalModuleAddress -= AlignedSize;
>+
>+ if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+ // Let it 64 byte align
>+ OptionalModuleAddress = (UINT8 *)((UINTN)OptionalModuleAddress &
>~BIOS_MODULE_ALIGNMENT);
>+ }
>+
>+ for (SubIndex = 0; SubIndex < (INTN)(AlignedSize); SubIndex ++) {
>+ if (OptionalModuleAddress[SubIndex] != 0xFF) {
>+ //
>+ // No enough space - it might happen that it is occupied by AP wake
>vector.
>+ // Last chance - skip this and search again.
>+ //
>+ OptionalModuleAddress = FindSpaceSkipApVector (FvBuffer,
>&OptionalModuleAddress[SubIndex], AlignedSize);
>+ if (OptionalModuleAddress == NULL) {
>+ Error (NULL, 0, 0, "No enough space for OptionalModule!", NULL);
>+ return NULL;
>+ }
>+ }
>+ }
>+ memcpy (OptionalModuleAddress, (VOID *) (UINTN)
>gFitTableContext.OptionalModule[Index].Address,
>gFitTableContext.OptionalModule[Index].Size);
>+ free ((VOID *) (UINTN)
>gFitTableContext.OptionalModule[Index].Address);
>+ gFitTableContext.OptionalModule[Index].Address = MEMORY_TO_FLASH
>(OptionalModuleAddress, FvBuffer, FvSize);
>+ }
>+ //
>+ // Final: Check BiosPolicyData in BiosModule.
>+ //
>+ if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+ (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+ CheckOverlap (gFitTableContext.OptionalModule[Index].Address,
>AlignedSize);
>+ }
>+ }
>+
>+ return FitTableOffset;
>+}
>+
>+VOID
>+PrintFitData (
>+ VOID
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Output FIT table information
>+
>+Arguments:
>+
>+ None
>+
>+Returns:
>+
>+ None
>+
>+--*/
>+{
>+ UINT32 Index;
>+
>+ printf ("FIT Table Pointer Offset: 0x%x\n",
>gFitTableContext.FitTablePointerOffset);
>+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+ printf ("FIT Table Pointer Offset: 0x%x\n",
>gFitTableContext.FitTablePointerOffset2);
>+ }
>+ printf ("Total FIT Entry number: 0x%x\n",
>gFitTableContext.FitEntryNumber);
>+ printf ("FitHeader version: 0x%04x\n", gFitTableContext.FitHeaderVersion);
>+ if (gFitTableContext.StartupAcm.Address != 0) {
>+ printf ("StartupAcm - (0x%08x, 0x%08x, 0x%04x)\n",
>gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size,
>gFitTableContext.StartupAcmVersion);
>+ }
>+ for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
>+ printf ("BiosModule[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index,
>gFitTableContext.BiosModule[Index].Address,
>gFitTableContext.BiosModule[Index].Size,
>gFitTableContext.BiosModuleVersion);
>+ }
>+ for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
>+ printf ("Microcode[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index,
>gFitTableContext.Microcode[Index].Address,
>gFitTableContext.Microcode[Index].Size,
>gFitTableContext.MicrocodeVersion);
>+ }
>+ for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++)
>{
>+ printf ("OptionalModule[%d] - (0x%08x, 0x%08x, 0x%02x, 0x%04x)\n",
>Index, gFitTableContext.OptionalModule[Index].Address,
>gFitTableContext.OptionalModule[Index].Size,
>gFitTableContext.OptionalModule[Index].Type,
>gFitTableContext.OptionalModule[Index].Version);
>+ }
>+ for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
>+ printf ("PortModule[%d] - (0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%04x,
>0x%02x, 0x%04x)\n", Index,
>+ (UINT16)gFitTableContext.PortModule[Index].Address,
>(UINT16)(gFitTableContext.PortModule[Index].Address >> 16),
>+ (UINT8)gFitTableContext.PortModule[Index].Size,
>(UINT8)(gFitTableContext.PortModule[Index].Size >> 8),
>(UINT16)(gFitTableContext.PortModule[Index].Size >> 16),
>+ gFitTableContext.PortModule[Index].Type,
>gFitTableContext.PortModule[Index].Version);
>+ }
>+
>+ printf ("\n");
>+ return ;
>+}
>+
>+CHAR8 *mFitTypeStr[] = {
>+ " ",
>+ "MICROCODE ",
>+ "STARTUP_ACM",
>+ " ",
>+ " ",
>+ " ",
>+ " ",
>+ "BIOS_MODULE",
>+ "TPM_POLICY ",
>+ "BIOS_POLICY",
>+ "TXT_POLICY ",
>+ "KEYMANIFEST",
>+ "BP_MANIFEST",
>+ "BIOS_DATA_A",
>+ " ",
>+ " ",
>+ "CSE_SECUREB"
>+};
>+
>+CHAR8 mFitSignature[] = "'_FIT_ ' ";
>+CHAR8 mFitSignatureInHeader[] = "' ' ";
>+CHAR8 *
>+FitTypeToStr (
>+ IN FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Convert FitEntry type to a string
>+
>+Arguments:
>+
>+ FitEntry - Fit entry
>+
>+Returns:
>+
>+ String
>+
>+--*/
>+{
>+ if (FitEntry->Type == FIT_TABLE_TYPE_HEADER) {
>+ CopyMem (&mFitSignatureInHeader[1], &FitEntry->Address,
>sizeof(FitEntry->Address));
>+ return mFitSignatureInHeader;
>+ }
>+ if (FitEntry->Type < sizeof (mFitTypeStr)/sizeof(mFitTypeStr[0])) {
>+ return mFitTypeStr[FitEntry->Type];
>+ } else {
>+ return " ";
>+ }
>+}
>+
>+VOID
>+PrintFitTable (
>+ IN UINT8 *FvBuffer,
>+ IN UINT32 FvSize
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Print Fit table in flash image
>+
>+Arguments:
>+
>+ FvBuffer - FvRecovery binary buffer
>+ FvSize - FvRecovery size
>+
>+Returns:
>+
>+ None
>+
>+--*/
>+{
>+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
>+ UINT32 EntryNum;
>+ UINT32 Index;
>+ UINT32 FitTableOffset;
>+ FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *FitEntryPort;
>+
>+ printf ("##############\n");
>+ printf ("# FIT Table: #\n");
>+ printf ("##############\n");
>+
>+ printf ("FIT Pointer Offset: 0x%x\n",
>gFitTableContext.FitTablePointerOffset);
>+ FitTableOffset = *(UINT32 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset);
>+ printf ("FIT Table Address: 0x%x\n", FitTableOffset);
>+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY
>*)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
>+
>+ //
>+ // Check FitEntry is 16 byte aligned
>+ //
>+ if (((UINTN)FitEntry & 0xF) != 0) {
>+ printf("ERROR: invalid FitEntry address 0x%X!\n", (UINT32) (UINTN)
>FitEntry);
>+ return;
>+ }
>+
>+ EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
>+ printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+ printf ("Index: Address Size Version Type C_V Checksum (Index
>Data Width Bit Offset)\n");
>+ printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+ for (Index = 0; Index < EntryNum; Index++) {
>+ printf (" %02d: %016llx %06x %04x %02x-%s %02x %02x ",
>+ Index,
>+ (unsigned long long) FitEntry[Index].Address,
>+ *(UINT32 *)(&FitEntry[Index].Size[0]) & 0xFFFFFF,
>+ FitEntry[Index].Version,
>+ FitEntry[Index].Type,
>+ FitTypeToStr(&FitEntry[Index]),
>+ FitEntry[Index].C_V,
>+ FitEntry[Index].Checksum
>+ );
>+
>+ if (Index == 0) {
>+ if (FitEntry[Index].Type != FIT_TABLE_TYPE_HEADER) {
>+ printf("ERROR: FIT Entry 0 is not Header Type %d!\n",
>FIT_TABLE_TYPE_HEADER);
>+ return;
>+ }
>+ if (strcmp(mFitSignatureInHeader, mFitSignature) != 0) {
>+ printf("ERROR: FIT Entry 0 signature invalid (%s, expected %s)!\n",
>mFitSignatureInHeader, mFitSignature);
>+ return;
>+ }
>+
>+ }
>+
>+ switch (FitEntry[Index].Type) {
>+ case FIT_TABLE_TYPE_TPM_POLICY:
>+ case FIT_TABLE_TYPE_TXT_POLICY:
>+ if (FitEntry[Index].Version == 0) {
>+ FitEntryPort = (FIRMWARE_INTERFACE_TABLE_ENTRY_PORT
>*)&FitEntry[Index];
>+ printf (" ( %04x %04x %02x %02x %04x )\n",
>+ FitEntryPort->IndexPort,
>+ FitEntryPort->DataPort,
>+ FitEntryPort->Width,
>+ FitEntryPort->Bit,
>+ FitEntryPort->Index
>+ );
>+ break;
>+ }
>+ // Not Port Configure, pass through
>+ default:
>+ printf ("\n");
>+ break;
>+ }
>+ }
>+ printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+ printf ("Index: Address Size Version Type C_V Checksum (Index
>Data Width Bit Offset)\n");
>+ printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+}
>+
>+/**
>+
>+ This function dump raw data.
>+
>+ @param Data raw data
>+ @param Size raw data size
>+
>+**/
>+VOID
>+DumpData (
>+ IN UINT8 *Data,
>+ IN UINT32 Size
>+ )
>+{
>+ UINT32 Index;
>+ for (Index = 0; Index < Size; Index++) {
>+ printf ("%02x", Data[Index]);
>+ }
>+}
>+
>+/**
>+
>+ This function dump raw data with colume format.
>+
>+ @param Data raw data
>+ @param Size raw data size
>+
>+**/
>+VOID
>+DumpHex (
>+ IN UINT8 *Data,
>+ IN UINT32 Size
>+ )
>+{
>+ UINT32 Index;
>+ UINT32 Count;
>+ UINT32 Left;
>+
>+#define COLUME_SIZE (16 * 2)
>+
>+ Count = Size / COLUME_SIZE;
>+ Left = Size % COLUME_SIZE;
>+ for (Index = 0; Index < Count; Index++) {
>+ printf ("%04x: ", Index * COLUME_SIZE);
>+ DumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
>+ printf ("\n");
>+ }
>+
>+ if (Left != 0) {
>+ printf ("%04x: ", Index * COLUME_SIZE);
>+ DumpData (Data + Index * COLUME_SIZE, Left);
>+ printf ("\n");
>+ }
>+}
>+
>+//
>+// This table defines the ACM type string
>+//
>+CHAR8 *mAcmTypeStr[] = {
>+ "BIOS ACM",
>+ "SINIT ACM",
>+};
>+
>+//
>+// This table defines the ACM capability string
>+//
>+CHAR8 *mCapabilityStr[] = {
>+ "GETSEC[WAKEUP] for RLP ",
>+ "MONITOR address for RLP ",
>+ "ECX for MLE PageTable ",
>+ "STM support ",
>+};
>+
>+VOID
>+DumpAcm (
>+ IN ACM_FORMAT *Acm
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ DumpAcm information
>+
>+Arguments:
>+
>+ Acm - ACM buffer
>+
>+Returns:
>+
>+ None
>+
>+--*/
>+{
>+ CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
>+ CHIPSET_ID_LIST *ChipsetIdList;
>+ PROCESSOR_ID_LIST *ProcessorIdList;
>+ UINT32 Index;
>+ UINT8 *Buffer;
>+
>+ printf (
>+
>"**********************************************************
>*******************\n"
>+ "* ACM *\n"
>+
>"**********************************************************
>*******************\n"
>+ );
>+
>+ printf ("ACM: (%08x)\n", (UINT32) (UINTN) Acm);
>+ printf (" ModuleType - %04x\n", Acm->ModuleType);
>+ if (Acm->ModuleType == ACM_MODULE_TYPE_CHIPSET_ACM) {
>+ printf (" Chipset ACM\n");
>+ }
>+ printf (" ModuleSubType - %04x\n", Acm->ModuleSubType);
>+ if ((Acm->ModuleSubType &
>ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET) != 0) {
>+ printf (" Capable of be Executed at Reset\n");
>+ }
>+ if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) != 0)
>{
>+ printf (" AnC Module\n");
>+ }
>+ printf (" HeaderLen - %08x\n", Acm->HeaderLen);
>+ printf (" HeaderVersion - %08x\n", Acm->HeaderVersion);
>+ printf (" ChipsetID - %04x\n", Acm->ChipsetID);
>+ printf (" Flags - %04x\n", Acm->Flags);
>+ printf (" PreProduction - %04x\n", Acm->Flags &
>ACM_MODULE_FLAG_PREPRODUCTION);
>+ printf (" Debug Signed - %04x\n", Acm->Flags &
>ACM_MODULE_FLAG_DEBUG_SIGN);
>+ printf (" ModuleVendor - %08x\n", Acm->ModuleVendor);
>+ printf (" Date - %08x\n", Acm->Date);
>+ printf (" Size - %08x\n", Acm->Size);
>+ printf (" TxtSvn - %04x\n", Acm->TxtSvn);
>+ printf (" SeSvn - %04x\n", Acm->SeSvn);
>+ printf (" CodeControl - %08x\n", Acm->CodeControl);
>+ printf (" ErrorEntryPoint - %08x\n", Acm->ErrorEntryPoint);
>+ printf (" GDTLimit - %08x\n", Acm->GDTLimit);
>+ printf (" GDTBasePtr - %08x\n", Acm->GDTBasePtr);
>+ printf (" SegSel - %08x\n", Acm->SegSel);
>+ printf (" EntryPoint - %08x\n", Acm->EntryPoint);
>+ printf (" KeySize - %08x\n", Acm->KeySize);
>+ printf (" ScratchSize - %08x\n", Acm->ScratchSize);
>+
>+ Buffer = (UINT8 *)(Acm + 1);
>+ printf (" RSAPubKey - \n");
>+ DumpHex (Buffer, Acm->KeySize * 4);
>+ printf ("\n");
>+ Buffer += Acm->KeySize * 4;
>+
>+ if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
>+ printf (" RSASig - \n");
>+ DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE); //
>PKCS #1.5 RSA Signature
>+ printf ("\n");
>+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
>+ } else {
>+ printf (" RSAPubExp - %08x\n", *(UINT32 *)Buffer);
>+ Buffer += 4;
>+
>+ printf (" RSASig - \n");
>+ DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE); //
>PKCS #1.5 RSA Signature
>+ printf ("\n");
>+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
>+ }
>+ Buffer += Acm->ScratchSize * 4;
>+
>+ if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) ==
>0) {
>+ ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE
>*)Buffer;
>+ printf ("Chipset ACM info:\n");
>+ printf (
>+ " Guid - {%08x-%08x-%08x-%08x}\n",
>+ ChipsetAcmInformationTable->Guid.Guid0,
>+ ChipsetAcmInformationTable->Guid.Guid1,
>+ ChipsetAcmInformationTable->Guid.Guid2,
>+ ChipsetAcmInformationTable->Guid.Guid3
>+ );
>+ printf (" ChipsetACMType - %02x\n", ChipsetAcmInformationTable-
>>ChipsetACMType);
>+ if (ChipsetAcmInformationTable->ChipsetACMType <
>sizeof(mAcmTypeStr)/sizeof(mAcmTypeStr[0])) {
>+ printf (" %s\n", mAcmTypeStr[ChipsetAcmInformationTable-
>>ChipsetACMType]);
>+ }
>+ printf (" Version - %02x\n", ChipsetAcmInformationTable-
>>Version);
>+ printf (" Length - %04x\n", ChipsetAcmInformationTable-
>>Length);
>+ printf (" ChipsetIDList - %08x\n", ChipsetAcmInformationTable-
>>ChipsetIDList);
>+ printf (" OsSinitTableVer - %08x\n", ChipsetAcmInformationTable-
>>OsSinitTableVer);
>+ printf (" MinMleHeaderVer - %08x\n", ChipsetAcmInformationTable-
>>MinMleHeaderVer);
>+ if (ChipsetAcmInformationTable->Version >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
>+ printf (" Capabilities - %08x\n", ChipsetAcmInformationTable-
>>Capabilities);
>+ for (Index = 0; Index < sizeof(mCapabilityStr)/sizeof(mCapabilityStr[0]);
>Index++) {
>+ if (mCapabilityStr[Index] == NULL) {
>+ continue;
>+ }
>+ printf (
>+ " %s- %08x\n",
>+ mCapabilityStr[Index],
>+ (ChipsetAcmInformationTable->Capabilities & (1 << Index))
>+ );
>+ }
>+ printf (" AcmVersion - %02x\n", ChipsetAcmInformationTable-
>>AcmVersion);
>+ printf (" AcmRevision - %02x.%02x.%02x\n",
>ChipsetAcmInformationTable->AcmRevision[0],
>ChipsetAcmInformationTable->AcmRevision[1],
>ChipsetAcmInformationTable->AcmRevision[2]);
>+ }
>+ if (ChipsetAcmInformationTable->Version >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
>+ printf (" ProcessorIDList - %08x\n", ChipsetAcmInformationTable-
>>ProcessorIDList);
>+ }
>+
>+ ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ChipsetIDList);
>+ printf ("Chipset ID List info:\n");
>+ printf (" Count - %08x\n", ChipsetIdList->Count);
>+ for (Index = 0; Index < ChipsetIdList->Count; Index++) {
>+ printf (" ID[%d]:\n", Index);
>+ printf (" Flags - %08x\n", ChipsetIdList-
>>ChipsetID[Index].Flags);
>+ printf (" RevisionIdMask - %08x\n", ChipsetIdList-
>>ChipsetID[Index].Flags & ACM_CHIPSET_ID_REVISION_ID_MAKE);
>+ printf (" VendorID - %04x\n", ChipsetIdList-
>>ChipsetID[Index].VendorID);
>+ printf (" DeviceID - %04x\n", ChipsetIdList-
>>ChipsetID[Index].DeviceID);
>+ printf (" RevisionID - %04x\n", ChipsetIdList-
>>ChipsetID[Index].RevisionID);
>+ }
>+ if (ChipsetAcmInformationTable->Version <
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
>+ goto End;
>+ }
>+ ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ProcessorIDList);
>+ printf ("Processor ID List info:\n");
>+ printf (" Count - %08x\n", ProcessorIdList->Count);
>+ for (Index = 0; Index < ProcessorIdList->Count; Index++) {
>+ printf (" ID[%d]:\n", Index);
>+ printf (" FMS - %08x\n", ProcessorIdList-
>>ProcessorID[Index].FMS);
>+ printf (" FMSMask - %08x\n", ProcessorIdList-
>>ProcessorID[Index].FMSMask);
>+ printf (" PlatformID - %016llx\n", (unsigned long long)
>ProcessorIdList->ProcessorID[Index].PlatformID);
>+ printf (" PlatformMask - %016llx\n", (unsigned long long)
>ProcessorIdList->ProcessorID[Index].PlatformMask);
>+ }
>+ }
>+
>+End:
>+ printf (
>+
>"**********************************************************
>*******************\n\n"
>+ );
>+}
>+
>+BOOLEAN
>+CheckAcm (
>+ IN ACM_FORMAT *Acm,
>+ IN UINTN AcmMaxSize
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Check Acm information
>+
>+Arguments:
>+
>+ Acm - ACM buffer
>+ AcmMaxSize - ACM max size
>+
>+Returns:
>+
>+ TRUE - ACM is valid
>+ FALSE - ACM is invalid
>+
>+--*/
>+{
>+ CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
>+ CHIPSET_ID_LIST *ChipsetIdList;
>+ PROCESSOR_ID_LIST *ProcessorIdList;
>+ UINT8 *Buffer;
>+
>+ if (Acm->ModuleType != ACM_MODULE_TYPE_CHIPSET_ACM) {
>+ printf ("ACM invalid : ModuleType!\n");
>+ return FALSE;
>+ }
>+ if (Acm->Size * 4 > AcmMaxSize) {
>+ printf ("ACM invalid : Size!\n");
>+ return FALSE;
>+ }
>+
>+ Buffer = (UINT8 *)(Acm + 1);
>+ Buffer += Acm->KeySize * 4;
>+ if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
>+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
>+ } else {
>+ Buffer += 4;
>+ Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
>+ }
>+ Buffer += Acm->ScratchSize * 4;
>+
>+ if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) ==
>0) {
>+ ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE
>*)Buffer;
>+ if ((UINTN)ChipsetAcmInformationTable >= (UINTN)Acm + AcmMaxSize) {
>+ printf ("ACM invalid : ChipsetAcmInformationTable!\n");
>+ return FALSE;
>+ }
>+
>+ if (CompareGuid ((EFI_GUID *)&ChipsetAcmInformationTable->Guid,
>(EFI_GUID *)&mChipsetAcmInformationTableGuid03) != 0) {
>+ printf ("ACM invalid : ChipsetACMGuid!\n");
>+ return FALSE;
>+ }
>+ if (ChipsetAcmInformationTable->ChipsetACMType !=
>CHIPSET_ACM_TYPE_BIOS) {
>+ printf ("ACM invalid : ChipsetACMType!\n");
>+ return FALSE;
>+ }
>+ if (ChipsetAcmInformationTable->Version <
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
>+ printf ("ACM invalid : ChipsetACMVersion!\n");
>+ return FALSE;
>+ }
>+ if ((UINTN)ChipsetAcmInformationTable + ChipsetAcmInformationTable-
>>Length > (UINTN)Acm + AcmMaxSize) {
>+ printf ("ACM invalid : ChipsetACMLength!\n");
>+ return FALSE;
>+ }
>+
>+ if (ChipsetAcmInformationTable->ChipsetIDList >= AcmMaxSize) {
>+ printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
>+ return FALSE;
>+ }
>+ ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ChipsetIDList);
>+ if (ChipsetIdList->Count == 0) {
>+ printf ("ACM invalid : ChipsetACMChipsetIDListCount!\n");
>+ return FALSE;
>+ }
>+ if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(CHIPSET_ID_LIST)
>+ (ChipsetIdList->Count - 1) * sizeof(ACM_CHIPSET_ID) > AcmMaxSize) {
>+ printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
>+ return FALSE;
>+ }
>+
>+ if (ChipsetAcmInformationTable->Version <
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
>+ goto End;
>+ }
>+
>+ if (ChipsetAcmInformationTable->ProcessorIDList >= AcmMaxSize) {
>+ printf ("ACM invalid : ChipsetACMProcessorIDList!\n");
>+ return FALSE;
>+ }
>+ ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ProcessorIDList);
>+ if (ProcessorIdList->Count == 0) {
>+ printf ("ACM invalid : ChipsetACMProcessorIdListCount!\n");
>+ return FALSE;
>+ }
>+ if (ChipsetAcmInformationTable->ChipsetIDList +
>sizeof(PROCESSOR_ID_LIST) + (ChipsetIdList->Count - 1) *
>sizeof(ACM_PROCESSOR_ID) > AcmMaxSize) {
>+ printf ("ACM invalid : ChipsetACMProcessorIdList!\n");
>+ return FALSE;
>+ }
>+ }
>+
>+End:
>+
>+ return TRUE;
>+}
>+
>+VOID
>+FillFitTable (
>+ IN UINT8 *FvBuffer,
>+ IN UINT32 FvSize,
>+ IN UINT8 *FitTableOffset
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Fill the FIT table information to FvRecovery
>+
>+Arguments:
>+
>+ FvBuffer - FvRecovery binary buffer
>+ FvSize - FvRecovery size
>+ FitTableOffset - The offset of FIT table in FvRecovery file
>+
>+Returns:
>+
>+ None
>+
>+--*/
>+{
>+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
>+ UINT32 FitIndex;
>+ UINT32 Index;
>+ UINT8 Checksum;
>+ UINTN SubIndex;
>+ FIT_TABLE_CONTEXT_ENTRY TempContextEntry;
>+ FIRMWARE_INTERFACE_TABLE_ENTRY TempTableEntry;
>+
>+ //
>+ // 1. FitPointer
>+ //
>+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) =
>(UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
>+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2)
>= (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
>+ }
>+
>+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FitTableOffset;
>+ FitIndex = 0;
>+
>+ //
>+ // 2. FitHeader
>+ //
>+ FitEntry[FitIndex].Address = *(UINT64 *)"_FIT_ ";
>+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.FitEntryNumber;
>+ FitEntry[FitIndex].Version =
>(UINT16)gFitTableContext.FitHeaderVersion;
>+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_HEADER;
>+ FitEntry[FitIndex].C_V = 1;
>+ //
>+ // Checksum will be updated later...
>+ //
>+ FitEntry[FitIndex].Checksum = 0;
>+
>+ //
>+ // 3. Microcode
>+ //
>+ FitIndex++;
>+ for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
>+ FitEntry[FitIndex].Address =
>gFitTableContext.Microcode[Index].Address;
>+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
>//gFitTableContext.Microcode[Index].Size / 16;
>+ FitEntry[FitIndex].Version =
>(UINT16)gFitTableContext.MicrocodeVersion;
>+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_MICROCODE;
>+ FitEntry[FitIndex].C_V = 0;
>+ FitEntry[FitIndex].Checksum = 0;
>+ FitIndex++;
>+ }
>+
>+ //
>+ // 4. StartupAcm
>+ //
>+ if (gFitTableContext.StartupAcm.Address != 0) {
>+ FitEntry[FitIndex].Address = gFitTableContext.StartupAcm.Address;
>+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
>//gFitTableContext.StartupAcm.Size / 16;
>+ FitEntry[FitIndex].Version =
>(UINT16)gFitTableContext.StartupAcmVersion;
>+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_STARTUP_ACM;
>+ FitEntry[FitIndex].C_V = 0;
>+ FitEntry[FitIndex].Checksum = 0;
>+ FitIndex++;
>+ }
>+
>+ //
>+ // 5. BiosModule
>+ //
>+ //
>+ // BiosModule segments order needs to be put from low addresss to high
>for Btg requirement
>+ //
>+ if (gFitTableContext.BiosModuleNumber > 1) {
>+ for (Index = 0; Index < (UINTN)gFitTableContext.BiosModuleNumber - 1;
>Index++){
>+ for (SubIndex = 0; SubIndex < gFitTableContext.BiosModuleNumber -
>Index - 1; SubIndex++) {
>+ if (gFitTableContext.BiosModule[SubIndex].Address >
>gFitTableContext.BiosModule[SubIndex + 1].Address) {
>+ CopyMem (&TempContextEntry,
>&gFitTableContext.BiosModule[SubIndex],
>sizeof(FIT_TABLE_CONTEXT_ENTRY));
>+ CopyMem (&gFitTableContext.BiosModule[SubIndex],
>&gFitTableContext.BiosModule[SubIndex + 1],
>sizeof(FIT_TABLE_CONTEXT_ENTRY));
>+ CopyMem (&gFitTableContext.BiosModule[SubIndex + 1],
>&TempContextEntry, sizeof(FIT_TABLE_CONTEXT_ENTRY));
>+ }
>+ }
>+ }
>+ }
>+ for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
>+ FitEntry[FitIndex].Address =
>gFitTableContext.BiosModule[Index].Address;
>+ *(UINT32 *)&FitEntry[FitIndex].Size[0] =
>gFitTableContext.BiosModule[Index].Size / 16;
>+ FitEntry[FitIndex].Version =
>(UINT16)gFitTableContext.BiosModuleVersion;
>+ FitEntry[FitIndex].Type = FIT_TABLE_TYPE_BIOS_MODULE;
>+ FitEntry[FitIndex].C_V = 0;
>+ FitEntry[FitIndex].Checksum = 0;
>+ FitIndex++;
>+ }
>+
>+ //
>+ // 6. Optional module
>+ //
>+ for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++)
>{
>+ FitEntry[FitIndex].Address =
>gFitTableContext.OptionalModule[Index].Address;
>+ *(UINT32 *)&FitEntry[FitIndex].Size[0] =
>gFitTableContext.OptionalModule[Index].Size;
>+ FitEntry[FitIndex].Version =
>(UINT16)gFitTableContext.OptionalModule[Index].Version;
>+ FitEntry[FitIndex].Type =
>(UINT8)gFitTableContext.OptionalModule[Index].Type;
>+ FitEntry[FitIndex].C_V = 0;
>+ FitEntry[FitIndex].Checksum = 0;
>+ FitIndex++;
>+ }
>+
>+ //
>+ // 7. Port module
>+ //
>+ for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
>+ FitEntry[FitIndex].Address =
>gFitTableContext.PortModule[Index].Address +
>((UINT64)gFitTableContext.PortModule[Index].Size << 32);
>+ *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
>+ FitEntry[FitIndex].Version =
>(UINT16)gFitTableContext.PortModule[Index].Version;
>+ FitEntry[FitIndex].Type =
>(UINT8)gFitTableContext.PortModule[Index].Type;
>+ FitEntry[FitIndex].C_V = 0;
>+ FitEntry[FitIndex].Checksum = 0;
>+ FitIndex++;
>+ }
>+
>+ //
>+ // The FIT records must always be arranged in the ascending order of their
>type attribute in the FIT.
>+ //
>+ for (Index = 0; Index < (UINTN)FitIndex - 1; Index++){
>+ for (SubIndex = 0; SubIndex < FitIndex - Index - 1; SubIndex++) {
>+ if (FitEntry[SubIndex].Type > FitEntry[SubIndex + 1].Type) {
>+ CopyMem (&TempTableEntry, &FitEntry[SubIndex],
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
>+ CopyMem (&FitEntry[SubIndex], &FitEntry[SubIndex + 1],
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
>+ CopyMem (&FitEntry[SubIndex + 1], &TempTableEntry,
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
>+ }
>+ }
>+ }
>+
>+ //
>+ // Update FIT header signature as final step
>+ //
>+ Checksum = CalculateChecksum8 ((UINT8 *)&FitEntry[0], sizeof
>(FIRMWARE_INTERFACE_TABLE_ENTRY) * FitIndex);
>+ FitEntry[0].Checksum = Checksum;
>+}
>+
>+VOID
>+ClearFitTable (
>+ IN UINT8 *FvBuffer,
>+ IN UINT32 FvSize
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Clear the FIT table information to Fvrecovery
>+
>+Arguments:
>+
>+ FvBuffer - Fvrecovery binary buffer
>+ FvSize - Fvrecovery size
>+
>+Returns:
>+
>+ None
>+
>+--*/
>+{
>+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
>+ UINT32 EntryNum;
>+ UINT32 FitIndex;
>+ UINT64 FitTablePointer;
>+ UINT8 *Buffer;
>+ UINT32 BufferSize;
>+
>+ FitTablePointer = *(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset);
>+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY
>(FitTablePointer, FvBuffer, FvSize);
>+
>+ //
>+ // Clear FIT pointer
>+ //
>+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) =
>0xEEEEEEEEEEEEEEEEull;
>+ if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+ *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2)
>= 0xEEEEEEEEEEEEEEEEull;
>+ }
>+
>+ //
>+ // Clear FIT table
>+ //
>+ EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
>+ for (FitIndex = 0; FitIndex < EntryNum; FitIndex++) {
>+ switch (FitEntry[FitIndex].Type) {
>+ case FIT_TABLE_TYPE_BIOS_POLICY:
>+ case FIT_TABLE_TYPE_KEY_MANIFEST:
>+ case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
>+ case FIT_TABLE_TYPE_BIOS_DATA_AREA:
>+ case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
>+ //
>+ // Clear FIT table data buffer
>+ //
>+ Buffer = FLASH_TO_MEMORY (FitEntry[FitIndex].Address, FvBuffer,
>FvSize);
>+ BufferSize = (*(UINT32 *)FitEntry[FitIndex].Size) & 0xFFFFFF;
>+ SetMem (Buffer, BufferSize, 0xFF);
>+ break;
>+ default:
>+ break;
>+ }
>+ //
>+ // Clear FIT table itself
>+ //
>+ SetMem (&FitEntry[FitIndex], sizeof(FitEntry[FitIndex]), 0xFF);
>+ }
>+}
>+
>+STATUS
>+WriteOutputFile (
>+ IN CHAR8 *FileName,
>+ IN UINT8 *FileData,
>+ IN UINT32 FileSize
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Read input file
>+
>+Arguments:
>+
>+ FileName - The input file name
>+ FileData - The input file data
>+ FileSize - The input file size
>+
>+Returns:
>+
>+ STATUS_SUCCESS - Write file data successfully
>+ STATUS_ERROR - The file data is not written
>+
>+--*/
>+{
>+ FILE *FpOut;
>+
>+ //
>+ // Open the output FvRecovery.fv file
>+ //
>+ if ((FpOut = fopen (FileName, "w+b")) == NULL) {
>+ Error (NULL, 0, 0, "Unable to open file", "%s", FileName);
>+ return STATUS_ERROR;
>+ }
>+ //
>+ // Write the output FvRecovery.fv file
>+ //
>+ if ((fwrite (FileData, 1, FileSize, FpOut)) != FileSize) {
>+ Error (NULL, 0, 0, "Write output file error!", NULL);
>+ fclose (FpOut);
>+ return STATUS_ERROR;
>+ }
>+
>+ //
>+ // Close the output FvRecovery.fv file
>+ //
>+ fclose (FpOut);
>+
>+ return STATUS_SUCCESS;
>+}
>+
>+UINT32
>+GetFvRecoveryInfoFromFd (
>+ IN UINT8 *FdBuffer,
>+ IN UINT32 FdFileSize,
>+ OUT UINT8 **FvRecovery
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Get FvRecovery information from Fd file.
>+
>+Arguments:
>+
>+ FdBuffer - Fd file buffer.
>+ FdFileSize - Fd file size.
>+ FvRecovery - FvRecovery pointer in Fd file buffer
>+
>+Returns:
>+ FvRecovery file size
>+
>+--*/
>+{
>+ UINT8 *FileBuffer = NULL;
>+ UINT32 FvRecoveryFileSize =0;
>+ EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
>+ UINT32 FvLength;
>+ UINT32 FileLength;
>+
>+ *FvRecovery = NULL;
>+ FileBuffer = FindNextFvHeader (FdBuffer, FdFileSize);
>+ if (FileBuffer == NULL) {
>+ return 0;
>+ }
>+
>+ while ((UINTN)FileBuffer < (UINTN)FdBuffer + FdFileSize) {
>+ FvLength = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER
>*)FileBuffer)->FvLength;
>+
>+ if (FindFileFromFvByGuid (FileBuffer, FvLength, &VTFGuid, &FileLength) !=
>NULL) {
>+ //
>+ // Found the VTF
>+ //
>+ FvRecoveryFileSize = FvLength;
>+ *FvRecovery = FileBuffer;
>+ }
>+
>+ //
>+ // Next fv
>+ //
>+ FileBuffer = (UINT8 *)FileBuffer + FvLength;
>+ if ((UINTN)FileBuffer >= (UINTN)FdBuffer + FdFileSize) {
>+ break;
>+ }
>+ FileBuffer = FindNextFvHeader (FileBuffer, (UINTN)FdBuffer + FdFileSize -
>(UINTN)FileBuffer);
>+ if (FileBuffer == NULL) {
>+ break;
>+ }
>+
>+ }
>+
>+ //
>+ // Return
>+ //
>+ return FvRecoveryFileSize;
>+}
>+
>+UINT32
>+GetFitEntryInfo (
>+ IN UINT8 *FvBuffer,
>+ IN UINT32 FvSize
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Fill the FIT table information to Fvrecovery
>+
>+Arguments:
>+
>+ FvBuffer - Fvrecovery binary buffer
>+ FvSize - Fvrecovery size
>+
>+Returns:
>+
>+ 0 - Fit Table not found
>+
>+--*/
>+{
>+ FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
>+ UINT32 FitIndex;
>+ UINT32 FitTableOffset;
>+
>+ //
>+ // 1. FitPointer
>+ //
>+ if (gFitTableContext.FitTablePointerOffset == 0) {
>+ gFitTableContext.FitTablePointerOffset =
>DEFAULT_FIT_TABLE_POINTER_OFFSET;
>+ }
>+ gFitTableContext.FitTablePointerOffset2 = 0;
>+
>+ FitTableOffset = *(UINT32 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset);
>+
>+ FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY
>*)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
>+ FitIndex = 0;
>+
>+ //
>+ // 2. FitHeader
>+ //
>+ if (FitEntry[FitIndex].Address != *(UINT64 *)"_FIT_ ") {
>+ return 0;
>+ }
>+ if (FitEntry[FitIndex].Type != FIT_TABLE_TYPE_HEADER) {
>+ return 0;
>+ }
>+ gFitTableContext.FitEntryNumber = *(UINT32 *)&FitEntry[FitIndex].Size[0];
>+ gFitTableContext.FitHeaderVersion = FitEntry[FitIndex].Version;
>+
>+ //
>+ // 3. FitEntry
>+ //
>+ FitIndex++;
>+ for (; FitIndex < gFitTableContext.FitEntryNumber; FitIndex++) {
>+ switch (FitEntry[FitIndex].Type) {
>+ case FIT_TABLE_TYPE_MICROCODE:
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>(UINT32)FitEntry[FitIndex].Address;
>+ gFitTableContext.MicrocodeVersion =
>FitEntry[FitIndex].Version;
>+ gFitTableContext.MicrocodeNumber ++;
>+ break;
>+ case FIT_TABLE_TYPE_STARTUP_ACM:
>+ gFitTableContext.StartupAcm.Address =
>(UINT32)FitEntry[FitIndex].Address;
>+ gFitTableContext.StartupAcmVersion = FitEntry[FitIndex].Version;
>+ break;
>+ case FIT_TABLE_TYPE_BIOS_MODULE:
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32)FitEntry[FitIndex].Address;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size =
>*(UINT32 *)&FitEntry[FitIndex].Size[0] * 16;
>+ gFitTableContext.BiosModuleVersion =
>FitEntry[FitIndex].Version;
>+ gFitTableContext.BiosModuleNumber ++;
>+ break;
>+ case FIT_TABLE_TYPE_TPM_POLICY:
>+ case FIT_TABLE_TYPE_TXT_POLICY:
>+ if (FitEntry[FitIndex].Version == 0) {
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Addres
>s = (UINT32)FitEntry[FitIndex].Address;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size =
>(UINT32)(FitEntry[FitIndex].Address >> 32);
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= FitEntry[FitIndex].Version;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type
>= FitEntry[FitIndex].Type;
>+ gFitTableContext.PortModuleNumber ++;
>+ break;
>+ }
>+ // Not Port Configure, pass through
>+ default: // Others
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Address = (UINT32)FitEntry[FitIndex].Address;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Size = *(UINT32 *)&FitEntry[FitIndex].Size[0];
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = FitEntry[FitIndex].Version;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Type = FitEntry[FitIndex].Type;
>+ gFitTableContext.OptionalModuleNumber ++;
>+ break;
>+ }
>+ }
>+
>+ return gFitTableContext.FitEntryNumber;
>+}
>+
>+STATUS
>+FitGen (
>+ IN INTN argc,
>+ IN CHAR8 **argv
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Main function for FitGen.
>+
>+Arguments:
>+
>+ argc - Number of command line parameters.
>+ argv - Array of pointers to parameter strings.
>+
>+Returns:
>+ STATUS_SUCCESS - Utility exits successfully.
>+ STATUS_ERROR - Some error occurred during execution.
>+
>+--*/
>+{
>+ UINT32 FvRecoveryFileSize;
>+ UINT8 *FileBuffer;
>+ UINT8 *FileBufferRaw;
>+ UINTN FitEntryNumber;
>+ UINT8 *FitTableOffset;
>+ STATUS Status;
>+ UINT32 FitTableSize;
>+
>+ BOOLEAN IsFv;
>+ UINT8 *FdFileBuffer;
>+ UINT32 FdFileSize;
>+
>+ UINT8 *AcmBuffer;
>+
>+ //
>+ // Step 0: Check FV or FD
>+ //
>+ if (((strcmp (argv[1], "-D") == 0) ||
>+ (strcmp (argv[1], "-d") == 0)) ) {
>+ IsFv = FALSE;
>+ } else {
>+ IsFv = TRUE;
>+ }
>+
>+ //
>+ // Step 1: Read InputFvRecovery.fv data
>+ //
>+ if (IsFv) {
>+ Status = ReadInputFile (argv[1], &FileBuffer, &FvRecoveryFileSize,
>&FileBufferRaw);
>+ if (Status != STATUS_SUCCESS) {
>+ Error (NULL, 0, 0, "Unable to open file", "%s", argv[1]);
>+ goto exitFunc;
>+ }
>+ FdFileBuffer = FileBuffer;
>+ FdFileSize = FvRecoveryFileSize;
>+ } else {
>+ Status = ReadInputFile (argv[2], &FdFileBuffer, &FdFileSize,
>&FileBufferRaw);
>+ if (Status != STATUS_SUCCESS) {
>+ Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
>+ goto exitFunc;
>+ }
>+
>+ //
>+ // Get Fvrecovery information
>+ //
>+ FvRecoveryFileSize = GetFvRecoveryInfoFromFd (FdFileBuffer, FdFileSize,
>&FileBuffer);
>+ if ((FvRecoveryFileSize == 0) || (FileBuffer == NULL)) {
>+ Error (NULL, 0, 0, "FvRecovery not found in Fd file!", NULL);
>+ Status = STATUS_ERROR;
>+ goto exitFunc;
>+ }
>+ }
>+
>+ //
>+ // Step 2: Calculate FIT entry number.
>+ //
>+ FitEntryNumber = GetFitEntryNumber (argc, argv, FdFileBuffer, FdFileSize);
>+ if (!gFitTableContext.Clear) {
>+ if (FitEntryNumber == 0) {
>+ Status = STATUS_ERROR;
>+ goto exitFunc;
>+ }
>+
>+ //
>+ // For debug
>+ //
>+ PrintFitData ();
>+
>+ //
>+ // Add 1 more FitEntry as place holder, because we need exclude FIT table
>itself
>+ //
>+ FitEntryNumber++;
>+
>+ //
>+ // Step 3: Get enough space in FvRecovery.fv
>+ //
>+ FitTableOffset = GetFreeSpaceFromFv (FileBuffer, FvRecoveryFileSize,
>FitEntryNumber);
>+ if (FitTableOffset == NULL) {
>+ return STATUS_ERROR;
>+ }
>+ FitTableSize = FitEntryNumber *
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
>+ FitTableSize += FIT_ALIGNMENT;
>+ FitTableSize &= ~FIT_ALIGNMENT;
>+
>+ CheckOverlap (
>+ MEMORY_TO_FLASH (FitTableOffset, FdFileBuffer, FdFileSize),
>+ FitTableSize
>+ );
>+
>+ //
>+ // Get ACM buffer
>+ //
>+ if (gFitTableContext.StartupAcm.Address != 0) {
>+ AcmBuffer = FLASH_TO_MEMORY(gFitTableContext.StartupAcm.Address,
>FdFileBuffer, FdFileSize);
>+ if ((AcmBuffer < FdFileBuffer) || (AcmBuffer +
>gFitTableContext.StartupAcm.Size > FdFileBuffer + FdFileSize)) {
>+ printf ("ACM out of range - can not validate it\n");
>+ AcmBuffer = NULL;
>+ }
>+
>+ if (AcmBuffer != NULL) {
>+ if (CheckAcm ((ACM_FORMAT *)AcmBuffer,
>gFitTableContext.StartupAcm.Size)) {
>+ DumpAcm ((ACM_FORMAT *)AcmBuffer);
>+ } else {
>+ Status = STATUS_ERROR;
>+ goto exitFunc;
>+ }
>+ }
>+
>+ }
>+
>+ //
>+ // Step 4: Fill the FIT table one by one
>+ //
>+ FillFitTable (FdFileBuffer, FdFileSize, FitTableOffset);
>+
>+ //
>+ // For debug
>+ //
>+ PrintFitTable (FdFileBuffer, FdFileSize);
>+ } else {
>+ printf ("Clear FIT table ...\n");
>+ //
>+ // Step 3: Get FIT table info
>+ //
>+ FitEntryNumber = GetFitEntryInfo (FdFileBuffer, FdFileSize);
>+ if (FitEntryNumber == 0) {
>+ Error (NULL, 0, 0, "No FIT table found", NULL);
>+ return STATUS_ERROR;
>+ }
>+
>+ //
>+ // For debug
>+ //
>+ PrintFitTable (FdFileBuffer, FdFileSize);
>+
>+ //
>+ // Step 4: Clear FIT table
>+ //
>+ ClearFitTable (FdFileBuffer, FdFileSize);
>+ printf ("Clear FIT table Done!\n");
>+ }
>+
>+ //
>+ // Step 5: Write OutputFvRecovery.fv data
>+ //
>+ if (IsFv) {
>+ Status = WriteOutputFile (argv[2], FileBuffer, FvRecoveryFileSize);
>+ } else {
>+ Status = WriteOutputFile (argv[3], FdFileBuffer, FdFileSize);
>+ }
>+
>+exitFunc:
>+ if (FileBufferRaw != NULL) {
>+ free ((VOID *)FileBufferRaw);
>+ }
>+ return Status;
>+}
>+
>+STATUS
>+FitView (
>+ IN INTN argc,
>+ IN CHAR8 **argv
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ View function for FitGen.
>+
>+Arguments:
>+
>+ argc - Number of command line parameters.
>+ argv - Array of pointers to parameter strings.
>+
>+Returns:
>+ STATUS_SUCCESS - Utility exits successfully.
>+ STATUS_ERROR - Some error occurred during execution.
>+
>+--*/
>+{
>+ UINT32 FvRecoveryFileSize;
>+ UINT8 *FileBuffer;
>+ UINT8 *FileBufferRaw = NULL;
>+ STATUS Status;
>+
>+ //
>+ // Step 1: Read input file
>+ //
>+ Status = ReadInputFile (argv[2], &FileBuffer, &FvRecoveryFileSize,
>&FileBufferRaw);
>+ if (Status != STATUS_SUCCESS) {
>+ Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
>+ goto exitFunc;
>+ }
>+
>+ // no -f option, use default FIT pointer offset
>+ if (argc == 3) {
>+ //
>+ // Use default address
>+ //
>+ gFitTableContext.FitTablePointerOffset =
>DEFAULT_FIT_TABLE_POINTER_OFFSET;
>+ } else if (stricmp (argv[3], "-f") == 0) {
>+ if (argc == 5) {
>+ //
>+ // Get offset from parameter
>+ //
>+ gFitTableContext.FitTablePointerOffset = xtoi (argv[3 + 1]);
>+ } else {
>+ Error (NULL, 0, 0, "FIT offset not specified!", NULL);
>+ goto exitFunc;
>+ }
>+ } else {
>+ Error (NULL, 0, 0, "Invalid view option: ", "%s", argv[3]);
>+ goto exitFunc;
>+ }
>+
>+ //
>+ // For debug
>+ //
>+ PrintFitTable (FileBuffer, FvRecoveryFileSize);
>+
>+exitFunc:
>+ if (FileBufferRaw != NULL) {
>+ free ((VOID *)FileBufferRaw);
>+ }
>+ return Status;
>+}
>+
>+int
>+main (
>+ int argc,
>+ char **argv
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Main function.
>+
>+Arguments:
>+
>+ argc - Number of command line parameters.
>+ argv - Array of pointers to parameter strings.
>+
>+Returns:
>+ STATUS_SUCCESS - Utility exits successfully.
>+ STATUS_ERROR - Some error occurred during execution.
>+
>+--*/
>+{
>+ SetUtilityName (UTILITY_NAME);
>+
>+ //
>+ // Display utility information
>+ //
>+ PrintUtilityInfo ();
>+
>+ //
>+ // Verify the correct number of arguments
>+ //
>+ if (argc >= MIN_VIEW_ARGS && stricmp (argv[1], "-view") == 0) {
>+ return FitView (argc, argv);
>+ } else if (argc >= MIN_ARGS) {
>+ return FitGen (argc, argv);
>+ } else {
>+ Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);
>+ PrintUsage ();
>+ return STATUS_ERROR;
>+ }
>+}
>+
>+unsigned int
>+xtoi (
>+ char *str
>+ )
>+/*++
>+
>+Routine Description:
>+
>+ Convert hex string to uint
>+
>+Arguments:
>+
>+ str - The string
>+
>+Returns:
>+
>+--*/
>+{
>+ unsigned int u;
>+ char c;
>+ unsigned int m;
>+
>+ if (str == NULL) {
>+ return 0;
>+ }
>+
>+ m = (unsigned int) -1 >> 4;
>+ //
>+ // skip preceeding white space
>+ //
>+ while (*str && *str == ' ') {
>+ str += 1;
>+ }
>+ //
>+ // skip preceeding zeros
>+ //
>+ while (*str && *str == '0') {
>+ str += 1;
>+ }
>+ //
>+ // skip preceeding x/X character
>+ //
>+ if (*str && (*str == 'x' || *str == 'X')) {
>+ str += 1;
>+ }
>+ //
>+ // convert hex digits
>+ //
>+ u = 0;
>+ c = *(str++);
>+ while (c) {
>+ if (c >= 'a' && c <= 'f') {
>+ c -= 'a' - 'A';
>+ }
>+
>+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
>+ if (u > m) {
>+ return (unsigned int) -1;
>+ }
>+
>+ u = (u << 4) | (c - (c >= 'A' ? 'A' - 10 : '0'));
>+ } else {
>+ //
>+ // Let application exit immediately
>+ //
>+ Error (NULL, 0, 0, "Hex value is expected!", NULL);
>+ exit (0);
>+ break;
>+ }
>+
>+ c = *(str++);
>+ }
>+
>+ return u;
>+}
>+
>diff --git a/Silicon/Intel/Tools/FitGen/FitGen.h
>b/Silicon/Intel/Tools/FitGen/FitGen.h
>new file mode 100644
>index 0000000000..9bd3f6824b
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/FitGen.h
>@@ -0,0 +1,48 @@
>+/**@file
>+Definitions for the FitGen utility.
>+
>+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+SPDX-License-Identifier: BSD-2-Clause-Patent
>+
>+**/
>+
>+#ifndef _FIT_GEN_H
>+#define _FIT_GEN_H
>+
>+#include <stdio.h>
>+#include <stdlib.h>
>+#define PI_SPECIFICATION_VERSION 0x00010000
>+#define EFI_FVH_PI_REVISION EFI_FVH_REVISION
>+#include <Common/UefiBaseTypes.h>
>+#include <Common/PiFirmwareFile.h>
>+#include <Common/PiFirmwareVolume.h>
>+#include <Guid/PiFirmwareFileSystem.h>
>+#include "EfiUtilityMsgs.c"
>+#include "CommonLib.h"
>+#include "ParseInf.h"
>+#include "FvLib.h"
>+
>+//
>+// Utility Name
>+//
>+#define UTILITY_NAME "FitGen"
>+
>+//
>+// Utility version information
>+//
>+#define UTILITY_MAJOR_VERSION 0
>+#define UTILITY_MINOR_VERSION 56
>+#define UTILITY_DATE __DATE__
>+
>+//
>+// The minimum number of arguments accepted from the command line.
>+//
>+#define MIN_VIEW_ARGS 3
>+#define MIN_ARGS 4
>+#define BUF_SIZE (8 * 1024)
>+
>+#define GETOCCUPIEDSIZE(ActualSize, Alignment) \
>+ (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) &
>((Alignment) - 1))
>+;
>+
>+#endif
>diff --git a/Silicon/Intel/Tools/FitGen/GNUmakefile
>b/Silicon/Intel/Tools/FitGen/GNUmakefile
>new file mode 100644
>index 0000000000..00a99bb0c7
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/GNUmakefile
>@@ -0,0 +1,16 @@
>+# @file
>+# GNUmakefile for building the FitGen utility.
>+#
>+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+#
>+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
>+
>+APPNAME = FitGen
>+
>+OBJECTS = FitGen.o
>+
>+include $(MAKEROOT)/Makefiles/app.makefile
>+
>+LIBS = -lCommon
>+
>diff --git a/Silicon/Intel/Tools/FitGen/Makefile
>b/Silicon/Intel/Tools/FitGen/Makefile
>new file mode 100644
>index 0000000000..fd286b26be
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/Makefile
>@@ -0,0 +1,17 @@
>+# @file
>+# makefile for building the FitGen utility.
>+#
>+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+#
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
>+
>+APPNAME = FitGen
>+
>+LIBS = $(LIB_PATH)\Common.lib
>+
>+OBJECTS = FitGen.obj
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
>+
>--
>2.18.0.windows.1
>
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile
2019-06-21 1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
` (4 preceding siblings ...)
2019-06-21 1:26 ` [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Zhang, Shenglei
@ 2019-06-21 1:26 ` Zhang, Shenglei
2019-06-26 2:04 ` Liming Gao
2019-06-21 2:25 ` [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Yao, Jiewen
6 siblings, 1 reply; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21 1:26 UTC (permalink / raw)
To: devel; +Cc: Bob Feng, Liming Gao
Add FitGen into Makefile and GNUMakefile.
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
Silicon/Intel/Tools/GNUmakefile | 34 +++++++++++++++++++++++++++++++++
Silicon/Intel/Tools/Makefile | 31 ++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
create mode 100644 Silicon/Intel/Tools/GNUmakefile
create mode 100644 Silicon/Intel/Tools/Makefile
diff --git a/Silicon/Intel/Tools/GNUmakefile b/Silicon/Intel/Tools/GNUmakefile
new file mode 100644
index 0000000000..77cfc62250
--- /dev/null
+++ b/Silicon/Intel/Tools/GNUmakefile
@@ -0,0 +1,34 @@
+## @file
+# GNUmakefile for building C utilities.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+MAKEROOT = $(EDK_TOOLS_PATH)/Source/C
+
+APPLICATIONS = \
+ FitGen \
+
+SUBDIRS := $(APPLICATIONS)
+
+$(APPLICATIONS): $(MAKEROOT)/bin
+
+.PHONY: subdirs $(SUBDIRS)
+subdirs: $(SUBDIRS)
+$(SUBDIRS):
+ $(MAKE) -C $@
+
+.PHONY: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+$(patsubst %,%-clean,$(sort $(SUBDIRS))):
+ -$(MAKE) -C $(@:-clean=) clean
+
+clean: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+
diff --git a/Silicon/Intel/Tools/Makefile b/Silicon/Intel/Tools/Makefile
new file mode 100644
index 0000000000..e52c95b7b5
--- /dev/null
+++ b/Silicon/Intel/Tools/Makefile
@@ -0,0 +1,31 @@
+## @file
+# makefile for building C utilities.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPLICATIONS = \
+ FitGen \
+
+all: $(APPLICATIONS)
+ @echo.
+ @echo ######################
+ @echo # Build executables
+ @echo ######################
+ @if not exist $(BIN_PATH) mkdir $(BIN_PATH)
+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat all $**
+
+.PHONY: clean
+clean: $(APPLICATIONS)
+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat clean $**
+
+.PHONY: cleanall
+cleanall: $(APPLICATIONS)
+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat cleanall $**
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.rule
+
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile
2019-06-21 1:26 ` [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
@ 2019-06-26 2:04 ` Liming Gao
0 siblings, 0 replies; 15+ messages in thread
From: Liming Gao @ 2019-06-26 2:04 UTC (permalink / raw)
To: Zhang, Shenglei, devel@edk2.groups.io; +Cc: Feng, Bob C
Shenglei:
See my comments.
Thanks
Liming
>-----Original Message-----
>From: Zhang, Shenglei
>Sent: Friday, June 21, 2019 9:27 AM
>To: devel@edk2.groups.io
>Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>
>Subject: [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and
>GNUMakefile
>
>Add FitGen into Makefile and GNUMakefile.
>
>Cc: Bob Feng <bob.c.feng@intel.com>
>Cc: Liming Gao <liming.gao@intel.com>
>Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
>---
> Silicon/Intel/Tools/GNUmakefile | 34
>+++++++++++++++++++++++++++++++++
> Silicon/Intel/Tools/Makefile | 31 ++++++++++++++++++++++++++++++
> 2 files changed, 65 insertions(+)
> create mode 100644 Silicon/Intel/Tools/GNUmakefile
> create mode 100644 Silicon/Intel/Tools/Makefile
>
>diff --git a/Silicon/Intel/Tools/GNUmakefile
>b/Silicon/Intel/Tools/GNUmakefile
>new file mode 100644
>index 0000000000..77cfc62250
>--- /dev/null
>+++ b/Silicon/Intel/Tools/GNUmakefile
>@@ -0,0 +1,34 @@
>+## @file
>+# GNUmakefile for building C utilities.
>+#
>+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
>+# This software and associated documentation (if any) is furnished
>+# under a license and may only be used or copied in accordance
>+# with the terms of the license. Except as permitted by such
>+# license, no part of this software or documentation may be
>+# reproduced, stored in a retrieval system, or transmitted in any
>+# form or by any means without the express written consent of
>+# Intel Corporation.
>+#
>+##
Please update license for BSD + Patent.
Thanks
Liming
>+
>+MAKEROOT = $(EDK_TOOLS_PATH)/Source/C
>+
>+APPLICATIONS = \
>+ FitGen \
>+
>+SUBDIRS := $(APPLICATIONS)
>+
>+$(APPLICATIONS): $(MAKEROOT)/bin
>+
>+.PHONY: subdirs $(SUBDIRS)
>+subdirs: $(SUBDIRS)
>+$(SUBDIRS):
>+ $(MAKE) -C $@
>+
>+.PHONY: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
>+$(patsubst %,%-clean,$(sort $(SUBDIRS))):
>+ -$(MAKE) -C $(@:-clean=) clean
>+
>+clean: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
>+
>diff --git a/Silicon/Intel/Tools/Makefile b/Silicon/Intel/Tools/Makefile
>new file mode 100644
>index 0000000000..e52c95b7b5
>--- /dev/null
>+++ b/Silicon/Intel/Tools/Makefile
>@@ -0,0 +1,31 @@
>+## @file
>+# makefile for building C utilities.
>+#
>+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+#
>+##
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
>+
>+APPLICATIONS = \
>+ FitGen \
>+
>+all: $(APPLICATIONS)
>+ @echo.
>+ @echo ######################
>+ @echo # Build executables
>+ @echo ######################
>+ @if not exist $(BIN_PATH) mkdir $(BIN_PATH)
>+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat all $**
>+
>+.PHONY: clean
>+clean: $(APPLICATIONS)
>+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat clean $**
>+
>+.PHONY: cleanall
>+cleanall: $(APPLICATIONS)
>+ @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat cleanall
>$**
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.rule
>+
>--
>2.18.0.windows.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
2019-06-21 1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
` (5 preceding siblings ...)
2019-06-21 1:26 ` [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
@ 2019-06-21 2:25 ` Yao, Jiewen
2019-06-21 2:31 ` Liming Gao
6 siblings, 1 reply; 15+ messages in thread
From: Yao, Jiewen @ 2019-06-21 2:25 UTC (permalink / raw)
To: devel@edk2.groups.io, Zhang, Shenglei
Cc: Feng, Bob C, Gao, Liming, Yao, Jiewen
HI
I saw some conflict:
=========
BaseTools/FCE: Add a tool FCE
Add FMMT and FCE into Platform/Intel/Tools.
=========
I agree that FitGet goes to Intel silicon.
Should we put both FCE/FMMT to BaseTools?
Thank you
Yao Jiewen
> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Zhang, Shenglei
> Sent: Friday, June 21, 2019 9:27 AM
> To: devel@edk2.groups.io
> Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> <liming.gao@intel.com>
> Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> FitGen
>
> Add FMMT and FCE into Platform/Intel/Tools.
> Add FitGen into Silicon/Intel/Tools.
> https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> https://bugzilla.tianocore.org/show_bug.cgi?id=1849
>
> Cc: Bob Feng <bob.c.feng@intel.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Shenglei Zhang (6):
> Platform/Tools: Add a tool FMMT
> Platform/Tools: Add a tool BfmLib
> BaseTools/FCE: Add a tool FCE
> Platform/Tools: Add top level Makefile and GNUMakefile
> Silicon/Tools: Add a tool FitGen
> Silicon/Tools: Add top level Makefile and GNUMakefile
>
> Platform/Intel/Tools/BfmLib/BfmLib.c | 4355 +++++++++++
> Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 +++
> Platform/Intel/Tools/BfmLib/BinFileManager.h | 439 ++
> Platform/Intel/Tools/BfmLib/GNUmakefile | 15 +
> Platform/Intel/Tools/BfmLib/Makefile | 17 +
> Platform/Intel/Tools/FCE/BinaryCreate.c | 216 +
> Platform/Intel/Tools/FCE/BinaryCreate.h | 157 +
> Platform/Intel/Tools/FCE/BinaryParse.c | 1326 ++++
> Platform/Intel/Tools/FCE/BinaryParse.h | 187 +
> Platform/Intel/Tools/FCE/Common.c | 2183 ++++++
> Platform/Intel/Tools/FCE/Common.h | 999 +++
> Platform/Intel/Tools/FCE/Expression.c | 2367 ++++++
> Platform/Intel/Tools/FCE/Fce.c | 6449
> +++++++++++++++++
> Platform/Intel/Tools/FCE/Fce.h | 447 ++
> Platform/Intel/Tools/FCE/GNUmakefile | 22 +
> Platform/Intel/Tools/FCE/IfrParse.c | 4836 ++++++++++++
> Platform/Intel/Tools/FCE/IfrParse.h | 789 ++
> Platform/Intel/Tools/FCE/Makefile | 19 +
> .../Intel/Tools/FCE/MonotonicBasedVariable.c | 874 +++
> .../Intel/Tools/FCE/MonotonicBasedVariable.h | 162 +
> Platform/Intel/Tools/FCE/TimeBasedVariable.c | 878 +++
> Platform/Intel/Tools/FCE/TimeBasedVariable.h | 166 +
> Platform/Intel/Tools/FCE/Variable.c | 1091 +++
> Platform/Intel/Tools/FCE/Variable.h | 154 +
> Platform/Intel/Tools/FCE/VariableCommon.h | 55 +
> .../Tools/FMMT/FirmwareModuleManagement.c | 2559 +++++++
> .../Tools/FMMT/FirmwareModuleManagement.h | 479 ++
> Platform/Intel/Tools/FMMT/FmmtConf.ini | 6 +
> Platform/Intel/Tools/FMMT/FmmtLib.c | 5051
> +++++++++++++
> Platform/Intel/Tools/FMMT/GNUmakefile | 16 +
> Platform/Intel/Tools/FMMT/Makefile | 17 +
> Platform/Intel/Tools/FMMT/Rebase.c | 846 +++
> Platform/Intel/Tools/FMMT/Rebase.h | 31 +
> Platform/Intel/Tools/GNUmakefile | 30 +
> Platform/Intel/Tools/Makefile | 33 +
> Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++
> Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
> Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
> Silicon/Intel/Tools/FitGen/Makefile | 17 +
> Silicon/Intel/Tools/GNUmakefile | 34 +
> Silicon/Intel/Tools/Makefile | 31 +
> 41 files changed, 41578 insertions(+)
> create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
> create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
> create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> create mode 100644 Platform/Intel/Tools/FCE/Common.c
> create mode 100644 Platform/Intel/Tools/FCE/Common.h
> create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> create mode 100644 Platform/Intel/Tools/FCE/Makefile
> create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
> create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
> create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> create mode 100644
> Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> create mode 100644
> Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> create mode 100644 Platform/Intel/Tools/GNUmakefile
> create mode 100644 Platform/Intel/Tools/Makefile
> create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> create mode 100644 Silicon/Intel/Tools/GNUmakefile
> create mode 100644 Silicon/Intel/Tools/Makefile
>
> --
> 2.18.0.windows.1
>
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
2019-06-21 2:25 ` [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Yao, Jiewen
@ 2019-06-21 2:31 ` Liming Gao
2019-06-21 3:34 ` Yao, Jiewen
0 siblings, 1 reply; 15+ messages in thread
From: Liming Gao @ 2019-06-21 2:31 UTC (permalink / raw)
To: Yao, Jiewen, devel@edk2.groups.io, Zhang, Shenglei; +Cc: Feng, Bob C
Jiewen:
I give the comments https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FMMT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
I give new proposal https://edk2.groups.io/g/devel/message/42546 for those tools.
Thanks
Liming
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Friday, June 21, 2019 10:26 AM
> To: devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
>
> HI
> I saw some conflict:
> =========
> BaseTools/FCE: Add a tool FCE
> Add FMMT and FCE into Platform/Intel/Tools.
> =========
>
> I agree that FitGet goes to Intel silicon.
>
> Should we put both FCE/FMMT to BaseTools?
>
> Thank you
> Yao Jiewen
>
>
> > -----Original Message-----
> > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> > Zhang, Shenglei
> > Sent: Friday, June 21, 2019 9:27 AM
> > To: devel@edk2.groups.io
> > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > <liming.gao@intel.com>
> > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> > FitGen
> >
> > Add FMMT and FCE into Platform/Intel/Tools.
> > Add FitGen into Silicon/Intel/Tools.
> > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> >
> > Cc: Bob Feng <bob.c.feng@intel.com>
> > Cc: Liming Gao <liming.gao@intel.com>
> > Shenglei Zhang (6):
> > Platform/Tools: Add a tool FMMT
> > Platform/Tools: Add a tool BfmLib
> > BaseTools/FCE: Add a tool FCE
> > Platform/Tools: Add top level Makefile and GNUMakefile
> > Silicon/Tools: Add a tool FitGen
> > Silicon/Tools: Add top level Makefile and GNUMakefile
> >
> > Platform/Intel/Tools/BfmLib/BfmLib.c | 4355 +++++++++++
> > Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 +++
> > Platform/Intel/Tools/BfmLib/BinFileManager.h | 439 ++
> > Platform/Intel/Tools/BfmLib/GNUmakefile | 15 +
> > Platform/Intel/Tools/BfmLib/Makefile | 17 +
> > Platform/Intel/Tools/FCE/BinaryCreate.c | 216 +
> > Platform/Intel/Tools/FCE/BinaryCreate.h | 157 +
> > Platform/Intel/Tools/FCE/BinaryParse.c | 1326 ++++
> > Platform/Intel/Tools/FCE/BinaryParse.h | 187 +
> > Platform/Intel/Tools/FCE/Common.c | 2183 ++++++
> > Platform/Intel/Tools/FCE/Common.h | 999 +++
> > Platform/Intel/Tools/FCE/Expression.c | 2367 ++++++
> > Platform/Intel/Tools/FCE/Fce.c | 6449
> > +++++++++++++++++
> > Platform/Intel/Tools/FCE/Fce.h | 447 ++
> > Platform/Intel/Tools/FCE/GNUmakefile | 22 +
> > Platform/Intel/Tools/FCE/IfrParse.c | 4836 ++++++++++++
> > Platform/Intel/Tools/FCE/IfrParse.h | 789 ++
> > Platform/Intel/Tools/FCE/Makefile | 19 +
> > .../Intel/Tools/FCE/MonotonicBasedVariable.c | 874 +++
> > .../Intel/Tools/FCE/MonotonicBasedVariable.h | 162 +
> > Platform/Intel/Tools/FCE/TimeBasedVariable.c | 878 +++
> > Platform/Intel/Tools/FCE/TimeBasedVariable.h | 166 +
> > Platform/Intel/Tools/FCE/Variable.c | 1091 +++
> > Platform/Intel/Tools/FCE/Variable.h | 154 +
> > Platform/Intel/Tools/FCE/VariableCommon.h | 55 +
> > .../Tools/FMMT/FirmwareModuleManagement.c | 2559 +++++++
> > .../Tools/FMMT/FirmwareModuleManagement.h | 479 ++
> > Platform/Intel/Tools/FMMT/FmmtConf.ini | 6 +
> > Platform/Intel/Tools/FMMT/FmmtLib.c | 5051
> > +++++++++++++
> > Platform/Intel/Tools/FMMT/GNUmakefile | 16 +
> > Platform/Intel/Tools/FMMT/Makefile | 17 +
> > Platform/Intel/Tools/FMMT/Rebase.c | 846 +++
> > Platform/Intel/Tools/FMMT/Rebase.h | 31 +
> > Platform/Intel/Tools/GNUmakefile | 30 +
> > Platform/Intel/Tools/Makefile | 33 +
> > Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++
> > Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
> > Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
> > Silicon/Intel/Tools/FitGen/Makefile | 17 +
> > Silicon/Intel/Tools/GNUmakefile | 34 +
> > Silicon/Intel/Tools/Makefile | 31 +
> > 41 files changed, 41578 insertions(+)
> > create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
> > create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
> > create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > create mode 100644
> > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > create mode 100644
> > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > create mode 100644 Platform/Intel/Tools/GNUmakefile
> > create mode 100644 Platform/Intel/Tools/Makefile
> > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > create mode 100644 Silicon/Intel/Tools/Makefile
> >
> > --
> > 2.18.0.windows.1
> >
> >
> >
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
2019-06-21 2:31 ` Liming Gao
@ 2019-06-21 3:34 ` Yao, Jiewen
2019-06-25 14:09 ` Liming Gao
0 siblings, 1 reply; 15+ messages in thread
From: Yao, Jiewen @ 2019-06-21 3:34 UTC (permalink / raw)
To: Gao, Liming, devel@edk2.groups.io, Zhang, Shenglei; +Cc: Feng, Bob C
Sorry, I missed the first mail.
I saw there is no V2 tag in this series, so I think it is the first mail. My apology.
I have no concern on FitGen - it is Intel only. You can check in at first.
FMMT/FCE is common. I think BaseTools is more proper place.
"It is not validated" - it seems a weird justification to me.
Or does it mean, for any future feature Intel/ARM people contribute, we should treat Platform package as the first choice, just because the it is cross validated?
May I understand more on the rule we have today on what goes to EDK2 repo and what goes to EDK2-PLATFORM repo?
Thank you
Yao Jiewen
> -----Original Message-----
> From: Gao, Liming
> Sent: Friday, June 21, 2019 10:31 AM
> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> Shenglei <shenglei.zhang@intel.com>
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
>
> Jiewen:
> I give the comments
> https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
>
> I give new proposal https://edk2.groups.io/g/devel/message/42546 for
> those tools.
>
> Thanks
> Liming
> > -----Original Message-----
> > From: Yao, Jiewen
> > Sent: Friday, June 21, 2019 10:26 AM
> > To: devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
> >
> > HI
> > I saw some conflict:
> > =========
> > BaseTools/FCE: Add a tool FCE
> > Add FMMT and FCE into Platform/Intel/Tools.
> > =========
> >
> > I agree that FitGet goes to Intel silicon.
> >
> > Should we put both FCE/FMMT to BaseTools?
> >
> > Thank you
> > Yao Jiewen
> >
> >
> > > -----Original Message-----
> > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf
> Of
> > > Zhang, Shenglei
> > > Sent: Friday, June 21, 2019 9:27 AM
> > > To: devel@edk2.groups.io
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > <liming.gao@intel.com>
> > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> > > FitGen
> > >
> > > Add FMMT and FCE into Platform/Intel/Tools.
> > > Add FitGen into Silicon/Intel/Tools.
> > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > >
> > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > Cc: Liming Gao <liming.gao@intel.com>
> > > Shenglei Zhang (6):
> > > Platform/Tools: Add a tool FMMT
> > > Platform/Tools: Add a tool BfmLib
> > > BaseTools/FCE: Add a tool FCE
> > > Platform/Tools: Add top level Makefile and GNUMakefile
> > > Silicon/Tools: Add a tool FitGen
> > > Silicon/Tools: Add top level Makefile and GNUMakefile
> > >
> > > Platform/Intel/Tools/BfmLib/BfmLib.c | 4355 +++++++++++
> > > Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 +++
> > > Platform/Intel/Tools/BfmLib/BinFileManager.h | 439 ++
> > > Platform/Intel/Tools/BfmLib/GNUmakefile | 15 +
> > > Platform/Intel/Tools/BfmLib/Makefile | 17 +
> > > Platform/Intel/Tools/FCE/BinaryCreate.c | 216 +
> > > Platform/Intel/Tools/FCE/BinaryCreate.h | 157 +
> > > Platform/Intel/Tools/FCE/BinaryParse.c | 1326 ++++
> > > Platform/Intel/Tools/FCE/BinaryParse.h | 187 +
> > > Platform/Intel/Tools/FCE/Common.c | 2183 ++++++
> > > Platform/Intel/Tools/FCE/Common.h | 999 +++
> > > Platform/Intel/Tools/FCE/Expression.c | 2367 ++++++
> > > Platform/Intel/Tools/FCE/Fce.c | 6449
> > > +++++++++++++++++
> > > Platform/Intel/Tools/FCE/Fce.h | 447 ++
> > > Platform/Intel/Tools/FCE/GNUmakefile | 22 +
> > > Platform/Intel/Tools/FCE/IfrParse.c | 4836 ++++++++++++
> > > Platform/Intel/Tools/FCE/IfrParse.h | 789 ++
> > > Platform/Intel/Tools/FCE/Makefile | 19 +
> > > .../Intel/Tools/FCE/MonotonicBasedVariable.c | 874 +++
> > > .../Intel/Tools/FCE/MonotonicBasedVariable.h | 162 +
> > > Platform/Intel/Tools/FCE/TimeBasedVariable.c | 878 +++
> > > Platform/Intel/Tools/FCE/TimeBasedVariable.h | 166 +
> > > Platform/Intel/Tools/FCE/Variable.c | 1091 +++
> > > Platform/Intel/Tools/FCE/Variable.h | 154 +
> > > Platform/Intel/Tools/FCE/VariableCommon.h | 55 +
> > > .../Tools/FMMT/FirmwareModuleManagement.c | 2559 +++++++
> > > .../Tools/FMMT/FirmwareModuleManagement.h | 479 ++
> > > Platform/Intel/Tools/FMMT/FmmtConf.ini | 6 +
> > > Platform/Intel/Tools/FMMT/FmmtLib.c | 5051
> > > +++++++++++++
> > > Platform/Intel/Tools/FMMT/GNUmakefile | 16 +
> > > Platform/Intel/Tools/FMMT/Makefile | 17 +
> > > Platform/Intel/Tools/FMMT/Rebase.c | 846 +++
> > > Platform/Intel/Tools/FMMT/Rebase.h | 31 +
> > > Platform/Intel/Tools/GNUmakefile | 30 +
> > > Platform/Intel/Tools/Makefile | 33 +
> > > Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++
> > > Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
> > > Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
> > > Silicon/Intel/Tools/FitGen/Makefile | 17 +
> > > Silicon/Intel/Tools/GNUmakefile | 34 +
> > > Silicon/Intel/Tools/Makefile | 31 +
> > > 41 files changed, 41578 insertions(+)
> > > create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > > create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
> > > create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
> > > create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > > create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > > create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > > create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > > create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > > create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > > create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > > create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > > create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > > create mode 100644
> Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > > create mode 100644
> Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > > create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > > create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > > create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > > create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > > create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > > create mode 100644
> > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > > create mode 100644
> > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > > create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > > create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > > create mode 100644 Platform/Intel/Tools/GNUmakefile
> > > create mode 100644 Platform/Intel/Tools/Makefile
> > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > > create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > > create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > > create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > > create mode 100644 Silicon/Intel/Tools/Makefile
> > >
> > > --
> > > 2.18.0.windows.1
> > >
> > >
> > >
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
2019-06-21 3:34 ` Yao, Jiewen
@ 2019-06-25 14:09 ` Liming Gao
2019-06-25 14:14 ` Yao, Jiewen
0 siblings, 1 reply; 15+ messages in thread
From: Liming Gao @ 2019-06-25 14:09 UTC (permalink / raw)
To: Yao, Jiewen, devel@edk2.groups.io, Zhang, Shenglei,
ard.biesheuvel@linaro.org, leif.lindholm@linaro.org
Cc: Feng, Bob C
Jiewen:
For FCE/FMMT C tools, I only compile them on X64 Linux OS. I don't compile them on ARM or AARCH64 Linux OS for ARM native build. Now, edk2 BaseTools C tools top level Makefile supports ARM, AARCH64, IA32 and X64. If they don't pass build on ARM native Linux OS, this change will bring the break for some user. If we can avoid the break, I agree to add them into edk2 BaseTools.
Ard:
I have no ARM or AARCH64 Linux OS. Could you help compile FCE/FMMT tools in ARM or AARCH64 Linux OS? These patches are in https://github.com/shenglei10/edk2/commits/movetool. After pick those patches, you just need to type make in BaseTools directory and compile all C tools. FCE/FMMT are common tools to update FD/FV image binaries. FMMT is a tool to enable removal, addition and replacement of FFS files in FD image binaries. FCE is a tool to retrieve and change HII configuration data as the default NV variable in Firmware Device(*.fd) files. They are used in post build step to replace FFS or insert the default NV storage in FD image.
Thanks
Liming
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Friday, June 21, 2019 11:34 AM
> To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
>
> Sorry, I missed the first mail.
> I saw there is no V2 tag in this series, so I think it is the first mail. My apology.
>
> I have no concern on FitGen - it is Intel only. You can check in at first.
> FMMT/FCE is common. I think BaseTools is more proper place.
>
> "It is not validated" - it seems a weird justification to me.
> Or does it mean, for any future feature Intel/ARM people contribute, we should treat Platform package as the first choice, just because the
> it is cross validated?
>
> May I understand more on the rule we have today on what goes to EDK2 repo and what goes to EDK2-PLATFORM repo?
>
> Thank you
> Yao Jiewen
>
>
> > -----Original Message-----
> > From: Gao, Liming
> > Sent: Friday, June 21, 2019 10:31 AM
> > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > Shenglei <shenglei.zhang@intel.com>
> > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> >
> > Jiewen:
> > I give the comments
> > https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> > MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
> >
> > I give new proposal https://edk2.groups.io/g/devel/message/42546 for
> > those tools.
> >
> > Thanks
> > Liming
> > > -----Original Message-----
> > > From: Yao, Jiewen
> > > Sent: Friday, June 21, 2019 10:26 AM
> > > To: devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> > >
> > > HI
> > > I saw some conflict:
> > > =========
> > > BaseTools/FCE: Add a tool FCE
> > > Add FMMT and FCE into Platform/Intel/Tools.
> > > =========
> > >
> > > I agree that FitGet goes to Intel silicon.
> > >
> > > Should we put both FCE/FMMT to BaseTools?
> > >
> > > Thank you
> > > Yao Jiewen
> > >
> > >
> > > > -----Original Message-----
> > > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf
> > Of
> > > > Zhang, Shenglei
> > > > Sent: Friday, June 21, 2019 9:27 AM
> > > > To: devel@edk2.groups.io
> > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > <liming.gao@intel.com>
> > > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> > > > FitGen
> > > >
> > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > Add FitGen into Silicon/Intel/Tools.
> > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > > >
> > > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > > Cc: Liming Gao <liming.gao@intel.com>
> > > > Shenglei Zhang (6):
> > > > Platform/Tools: Add a tool FMMT
> > > > Platform/Tools: Add a tool BfmLib
> > > > BaseTools/FCE: Add a tool FCE
> > > > Platform/Tools: Add top level Makefile and GNUMakefile
> > > > Silicon/Tools: Add a tool FitGen
> > > > Silicon/Tools: Add top level Makefile and GNUMakefile
> > > >
> > > > Platform/Intel/Tools/BfmLib/BfmLib.c | 4355 +++++++++++
> > > > Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 +++
> > > > Platform/Intel/Tools/BfmLib/BinFileManager.h | 439 ++
> > > > Platform/Intel/Tools/BfmLib/GNUmakefile | 15 +
> > > > Platform/Intel/Tools/BfmLib/Makefile | 17 +
> > > > Platform/Intel/Tools/FCE/BinaryCreate.c | 216 +
> > > > Platform/Intel/Tools/FCE/BinaryCreate.h | 157 +
> > > > Platform/Intel/Tools/FCE/BinaryParse.c | 1326 ++++
> > > > Platform/Intel/Tools/FCE/BinaryParse.h | 187 +
> > > > Platform/Intel/Tools/FCE/Common.c | 2183 ++++++
> > > > Platform/Intel/Tools/FCE/Common.h | 999 +++
> > > > Platform/Intel/Tools/FCE/Expression.c | 2367 ++++++
> > > > Platform/Intel/Tools/FCE/Fce.c | 6449
> > > > +++++++++++++++++
> > > > Platform/Intel/Tools/FCE/Fce.h | 447 ++
> > > > Platform/Intel/Tools/FCE/GNUmakefile | 22 +
> > > > Platform/Intel/Tools/FCE/IfrParse.c | 4836 ++++++++++++
> > > > Platform/Intel/Tools/FCE/IfrParse.h | 789 ++
> > > > Platform/Intel/Tools/FCE/Makefile | 19 +
> > > > .../Intel/Tools/FCE/MonotonicBasedVariable.c | 874 +++
> > > > .../Intel/Tools/FCE/MonotonicBasedVariable.h | 162 +
> > > > Platform/Intel/Tools/FCE/TimeBasedVariable.c | 878 +++
> > > > Platform/Intel/Tools/FCE/TimeBasedVariable.h | 166 +
> > > > Platform/Intel/Tools/FCE/Variable.c | 1091 +++
> > > > Platform/Intel/Tools/FCE/Variable.h | 154 +
> > > > Platform/Intel/Tools/FCE/VariableCommon.h | 55 +
> > > > .../Tools/FMMT/FirmwareModuleManagement.c | 2559 +++++++
> > > > .../Tools/FMMT/FirmwareModuleManagement.h | 479 ++
> > > > Platform/Intel/Tools/FMMT/FmmtConf.ini | 6 +
> > > > Platform/Intel/Tools/FMMT/FmmtLib.c | 5051
> > > > +++++++++++++
> > > > Platform/Intel/Tools/FMMT/GNUmakefile | 16 +
> > > > Platform/Intel/Tools/FMMT/Makefile | 17 +
> > > > Platform/Intel/Tools/FMMT/Rebase.c | 846 +++
> > > > Platform/Intel/Tools/FMMT/Rebase.h | 31 +
> > > > Platform/Intel/Tools/GNUmakefile | 30 +
> > > > Platform/Intel/Tools/Makefile | 33 +
> > > > Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++
> > > > Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
> > > > Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
> > > > Silicon/Intel/Tools/FitGen/Makefile | 17 +
> > > > Silicon/Intel/Tools/GNUmakefile | 34 +
> > > > Silicon/Intel/Tools/Makefile | 31 +
> > > > 41 files changed, 41578 insertions(+)
> > > > create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > > > create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
> > > > create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
> > > > create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > > > create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > > > create mode 100644
> > Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > > > create mode 100644
> > Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > > > create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > > > create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > > > create mode 100644
> > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > > > create mode 100644
> > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > > > create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > > > create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > > > create mode 100644 Platform/Intel/Tools/GNUmakefile
> > > > create mode 100644 Platform/Intel/Tools/Makefile
> > > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > > > create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > > > create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > > > create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > > > create mode 100644 Silicon/Intel/Tools/Makefile
> > > >
> > > > --
> > > > 2.18.0.windows.1
> > > >
> > > >
> > > >
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
2019-06-25 14:09 ` Liming Gao
@ 2019-06-25 14:14 ` Yao, Jiewen
2019-06-25 15:20 ` Liming Gao
0 siblings, 1 reply; 15+ messages in thread
From: Yao, Jiewen @ 2019-06-25 14:14 UTC (permalink / raw)
To: Gao, Liming, devel@edk2.groups.io, Zhang, Shenglei,
ard.biesheuvel@linaro.org, leif.lindholm@linaro.org
Cc: Feng, Bob C
Thanks Liming.
I would treat that as *a general help request* to validate the BaseTool update on ARM/AARCH64 Linux OS.
If we can have Ard or any other ARM person to help validate a new base tool patch, that will be great.
In this case, it is about the new added FCE or FMMT.
In the future, maybe we have other C-tool update.
Should we add them to CC list in any tool patch?
Thank you
Yao Jiewen
> -----Original Message-----
> From: Gao, Liming
> Sent: Tuesday, June 25, 2019 10:09 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> Shenglei <shenglei.zhang@intel.com>; ard.biesheuvel@linaro.org;
> leif.lindholm@linaro.org
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
>
> Jiewen:
> For FCE/FMMT C tools, I only compile them on X64 Linux OS. I don't
> compile them on ARM or AARCH64 Linux OS for ARM native build. Now,
> edk2 BaseTools C tools top level Makefile supports ARM, AARCH64, IA32 and
> X64. If they don't pass build on ARM native Linux OS, this change will bring
> the break for some user. If we can avoid the break, I agree to add them into
> edk2 BaseTools.
>
> Ard:
> I have no ARM or AARCH64 Linux OS. Could you help compile FCE/FMMT
> tools in ARM or AARCH64 Linux OS? These patches are in
> https://github.com/shenglei10/edk2/commits/movetool. After pick those
> patches, you just need to type make in BaseTools directory and compile all C
> tools. FCE/FMMT are common tools to update FD/FV image binaries. FMMT
> is a tool to enable removal, addition and replacement of FFS files in FD
> image binaries. FCE is a tool to retrieve and change HII configuration data as
> the default NV variable in Firmware Device(*.fd) files. They are used in post
> build step to replace FFS or insert the default NV storage in FD image.
>
> Thanks
> Liming
> > -----Original Message-----
> > From: Yao, Jiewen
> > Sent: Friday, June 21, 2019 11:34 AM
> > To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang,
> Shenglei <shenglei.zhang@intel.com>
> > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
> >
> > Sorry, I missed the first mail.
> > I saw there is no V2 tag in this series, so I think it is the first mail. My
> apology.
> >
> > I have no concern on FitGen - it is Intel only. You can check in at first.
> > FMMT/FCE is common. I think BaseTools is more proper place.
> >
> > "It is not validated" - it seems a weird justification to me.
> > Or does it mean, for any future feature Intel/ARM people contribute, we
> should treat Platform package as the first choice, just because the
> > it is cross validated?
> >
> > May I understand more on the rule we have today on what goes to EDK2
> repo and what goes to EDK2-PLATFORM repo?
> >
> > Thank you
> > Yao Jiewen
> >
> >
> > > -----Original Message-----
> > > From: Gao, Liming
> > > Sent: Friday, June 21, 2019 10:31 AM
> > > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > > Shenglei <shenglei.zhang@intel.com>
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > > and FitGen
> > >
> > > Jiewen:
> > > I give the comments
> > >
> https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> > > MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
> > >
> > > I give new proposal https://edk2.groups.io/g/devel/message/42546
> for
> > > those tools.
> > >
> > > Thanks
> > > Liming
> > > > -----Original Message-----
> > > > From: Yao, Jiewen
> > > > Sent: Friday, June 21, 2019 10:26 AM
> > > > To: devel@edk2.groups.io; Zhang, Shenglei
> <shenglei.zhang@intel.com>
> > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT
> FCE
> > > and FitGen
> > > >
> > > > HI
> > > > I saw some conflict:
> > > > =========
> > > > BaseTools/FCE: Add a tool FCE
> > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > =========
> > > >
> > > > I agree that FitGet goes to Intel silicon.
> > > >
> > > > Should we put both FCE/FMMT to BaseTools?
> > > >
> > > > Thank you
> > > > Yao Jiewen
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On
> Behalf
> > > Of
> > > > > Zhang, Shenglei
> > > > > Sent: Friday, June 21, 2019 9:27 AM
> > > > > To: devel@edk2.groups.io
> > > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > > <liming.gao@intel.com>
> > > > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and
> > > > > FitGen
> > > > >
> > > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > > Add FitGen into Silicon/Intel/Tools.
> > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > > > >
> > > > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > > > Cc: Liming Gao <liming.gao@intel.com>
> > > > > Shenglei Zhang (6):
> > > > > Platform/Tools: Add a tool FMMT
> > > > > Platform/Tools: Add a tool BfmLib
> > > > > BaseTools/FCE: Add a tool FCE
> > > > > Platform/Tools: Add top level Makefile and GNUMakefile
> > > > > Silicon/Tools: Add a tool FitGen
> > > > > Silicon/Tools: Add top level Makefile and GNUMakefile
> > > > >
> > > > > Platform/Intel/Tools/BfmLib/BfmLib.c | 4355
> +++++++++++
> > > > > Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 +++
> > > > > Platform/Intel/Tools/BfmLib/BinFileManager.h | 439 ++
> > > > > Platform/Intel/Tools/BfmLib/GNUmakefile | 15 +
> > > > > Platform/Intel/Tools/BfmLib/Makefile | 17 +
> > > > > Platform/Intel/Tools/FCE/BinaryCreate.c | 216 +
> > > > > Platform/Intel/Tools/FCE/BinaryCreate.h | 157 +
> > > > > Platform/Intel/Tools/FCE/BinaryParse.c | 1326 ++++
> > > > > Platform/Intel/Tools/FCE/BinaryParse.h | 187 +
> > > > > Platform/Intel/Tools/FCE/Common.c | 2183 ++++++
> > > > > Platform/Intel/Tools/FCE/Common.h | 999 +++
> > > > > Platform/Intel/Tools/FCE/Expression.c | 2367 ++++++
> > > > > Platform/Intel/Tools/FCE/Fce.c | 6449
> > > > > +++++++++++++++++
> > > > > Platform/Intel/Tools/FCE/Fce.h | 447 ++
> > > > > Platform/Intel/Tools/FCE/GNUmakefile | 22 +
> > > > > Platform/Intel/Tools/FCE/IfrParse.c | 4836
> ++++++++++++
> > > > > Platform/Intel/Tools/FCE/IfrParse.h | 789 ++
> > > > > Platform/Intel/Tools/FCE/Makefile | 19 +
> > > > > .../Intel/Tools/FCE/MonotonicBasedVariable.c | 874 +++
> > > > > .../Intel/Tools/FCE/MonotonicBasedVariable.h | 162 +
> > > > > Platform/Intel/Tools/FCE/TimeBasedVariable.c | 878 +++
> > > > > Platform/Intel/Tools/FCE/TimeBasedVariable.h | 166 +
> > > > > Platform/Intel/Tools/FCE/Variable.c | 1091 +++
> > > > > Platform/Intel/Tools/FCE/Variable.h | 154 +
> > > > > Platform/Intel/Tools/FCE/VariableCommon.h | 55 +
> > > > > .../Tools/FMMT/FirmwareModuleManagement.c | 2559
> +++++++
> > > > > .../Tools/FMMT/FirmwareModuleManagement.h | 479 ++
> > > > > Platform/Intel/Tools/FMMT/FmmtConf.ini | 6 +
> > > > > Platform/Intel/Tools/FMMT/FmmtLib.c | 5051
> > > > > +++++++++++++
> > > > > Platform/Intel/Tools/FMMT/GNUmakefile | 16 +
> > > > > Platform/Intel/Tools/FMMT/Makefile | 17 +
> > > > > Platform/Intel/Tools/FMMT/Rebase.c | 846 +++
> > > > > Platform/Intel/Tools/FMMT/Rebase.h | 31 +
> > > > > Platform/Intel/Tools/GNUmakefile | 30 +
> > > > > Platform/Intel/Tools/Makefile | 33 +
> > > > > Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++
> > > > > Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
> > > > > Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
> > > > > Silicon/Intel/Tools/FitGen/Makefile | 17 +
> > > > > Silicon/Intel/Tools/GNUmakefile | 34 +
> > > > > Silicon/Intel/Tools/Makefile | 31 +
> > > > > 41 files changed, 41578 insertions(+)
> > > > > create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > > > > create mode 100644
> Platform/Intel/Tools/BfmLib/BinFileManager.c
> > > > > create mode 100644
> Platform/Intel/Tools/BfmLib/BinFileManager.h
> > > > > create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > > > > create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > > > > create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > > > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > > > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > > > > create mode 100644
> > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > > > > create mode 100644
> > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > > > > create mode 100644
> Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > > > > create mode 100644
> Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > > > > create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > > > > create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > > > > create mode 100644
> > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > > > > create mode 100644
> > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > > > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > > > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > > > > create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > > > > create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > > > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > > > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > > > > create mode 100644 Platform/Intel/Tools/GNUmakefile
> > > > > create mode 100644 Platform/Intel/Tools/Makefile
> > > > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > > > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > > > > create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > > > > create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > > > > create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > > > > create mode 100644 Silicon/Intel/Tools/Makefile
> > > > >
> > > > > --
> > > > > 2.18.0.windows.1
> > > > >
> > > > >
> > > > >
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
2019-06-25 14:14 ` Yao, Jiewen
@ 2019-06-25 15:20 ` Liming Gao
0 siblings, 0 replies; 15+ messages in thread
From: Liming Gao @ 2019-06-25 15:20 UTC (permalink / raw)
To: Yao, Jiewen, devel@edk2.groups.io, Zhang, Shenglei,
ard.biesheuvel@linaro.org, leif.lindholm@linaro.org
Cc: Feng, Bob C, Gao, Liming
Jiewen:
Thanks
Liming
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Tuesday, June 25, 2019 10:15 PM
> To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>; ard.biesheuvel@linaro.org;
> leif.lindholm@linaro.org
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
>
> Thanks Liming.
>
> I would treat that as *a general help request* to validate the BaseTool update on ARM/AARCH64 Linux OS.
>
Yes. This is a help request.
> If we can have Ard or any other ARM person to help validate a new base tool patch, that will be great.
>
> In this case, it is about the new added FCE or FMMT.
> In the future, maybe we have other C-tool update.
>
> Should we add them to CC list in any tool patch?
>
FCE and FMMT are new tools with lots of source code. If they meet with the compile failure, it may take more effort to fix them.
So, I want to verify them before submit the patches. If the code change is not big, the developer can fix the error quickly
after the code is submitted. That's also fine to verify the change after submit.
Thanks
Liming
>
> Thank you
> Yao Jiewen
>
> > -----Original Message-----
> > From: Gao, Liming
> > Sent: Tuesday, June 25, 2019 10:09 PM
> > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > Shenglei <shenglei.zhang@intel.com>; ard.biesheuvel@linaro.org;
> > leif.lindholm@linaro.org
> > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> >
> > Jiewen:
> > For FCE/FMMT C tools, I only compile them on X64 Linux OS. I don't
> > compile them on ARM or AARCH64 Linux OS for ARM native build. Now,
> > edk2 BaseTools C tools top level Makefile supports ARM, AARCH64, IA32 and
> > X64. If they don't pass build on ARM native Linux OS, this change will bring
> > the break for some user. If we can avoid the break, I agree to add them into
> > edk2 BaseTools.
> >
> > Ard:
> > I have no ARM or AARCH64 Linux OS. Could you help compile FCE/FMMT
> > tools in ARM or AARCH64 Linux OS? These patches are in
> > https://github.com/shenglei10/edk2/commits/movetool. After pick those
> > patches, you just need to type make in BaseTools directory and compile all C
> > tools. FCE/FMMT are common tools to update FD/FV image binaries. FMMT
> > is a tool to enable removal, addition and replacement of FFS files in FD
> > image binaries. FCE is a tool to retrieve and change HII configuration data as
> > the default NV variable in Firmware Device(*.fd) files. They are used in post
> > build step to replace FFS or insert the default NV storage in FD image.
> >
> > Thanks
> > Liming
> > > -----Original Message-----
> > > From: Yao, Jiewen
> > > Sent: Friday, June 21, 2019 11:34 AM
> > > To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang,
> > Shenglei <shenglei.zhang@intel.com>
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> > >
> > > Sorry, I missed the first mail.
> > > I saw there is no V2 tag in this series, so I think it is the first mail. My
> > apology.
> > >
> > > I have no concern on FitGen - it is Intel only. You can check in at first.
> > > FMMT/FCE is common. I think BaseTools is more proper place.
> > >
> > > "It is not validated" - it seems a weird justification to me.
> > > Or does it mean, for any future feature Intel/ARM people contribute, we
> > should treat Platform package as the first choice, just because the
> > > it is cross validated?
> > >
> > > May I understand more on the rule we have today on what goes to EDK2
> > repo and what goes to EDK2-PLATFORM repo?
> > >
> > > Thank you
> > > Yao Jiewen
> > >
> > >
> > > > -----Original Message-----
> > > > From: Gao, Liming
> > > > Sent: Friday, June 21, 2019 10:31 AM
> > > > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > > > Shenglei <shenglei.zhang@intel.com>
> > > > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > > > and FitGen
> > > >
> > > > Jiewen:
> > > > I give the comments
> > > >
> > https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> > > > MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
> > > >
> > > > I give new proposal https://edk2.groups.io/g/devel/message/42546
> > for
> > > > those tools.
> > > >
> > > > Thanks
> > > > Liming
> > > > > -----Original Message-----
> > > > > From: Yao, Jiewen
> > > > > Sent: Friday, June 21, 2019 10:26 AM
> > > > > To: devel@edk2.groups.io; Zhang, Shenglei
> > <shenglei.zhang@intel.com>
> > > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > > > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT
> > FCE
> > > > and FitGen
> > > > >
> > > > > HI
> > > > > I saw some conflict:
> > > > > =========
> > > > > BaseTools/FCE: Add a tool FCE
> > > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > > =========
> > > > >
> > > > > I agree that FitGet goes to Intel silicon.
> > > > >
> > > > > Should we put both FCE/FMMT to BaseTools?
> > > > >
> > > > > Thank you
> > > > > Yao Jiewen
> > > > >
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On
> > Behalf
> > > > Of
> > > > > > Zhang, Shenglei
> > > > > > Sent: Friday, June 21, 2019 9:27 AM
> > > > > > To: devel@edk2.groups.io
> > > > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > > > <liming.gao@intel.com>
> > > > > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and
> > > > > > FitGen
> > > > > >
> > > > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > > > Add FitGen into Silicon/Intel/Tools.
> > > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > > > > >
> > > > > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > > > > Cc: Liming Gao <liming.gao@intel.com>
> > > > > > Shenglei Zhang (6):
> > > > > > Platform/Tools: Add a tool FMMT
> > > > > > Platform/Tools: Add a tool BfmLib
> > > > > > BaseTools/FCE: Add a tool FCE
> > > > > > Platform/Tools: Add top level Makefile and GNUMakefile
> > > > > > Silicon/Tools: Add a tool FitGen
> > > > > > Silicon/Tools: Add top level Makefile and GNUMakefile
> > > > > >
> > > > > > Platform/Intel/Tools/BfmLib/BfmLib.c | 4355
> > +++++++++++
> > > > > > Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 +++
> > > > > > Platform/Intel/Tools/BfmLib/BinFileManager.h | 439 ++
> > > > > > Platform/Intel/Tools/BfmLib/GNUmakefile | 15 +
> > > > > > Platform/Intel/Tools/BfmLib/Makefile | 17 +
> > > > > > Platform/Intel/Tools/FCE/BinaryCreate.c | 216 +
> > > > > > Platform/Intel/Tools/FCE/BinaryCreate.h | 157 +
> > > > > > Platform/Intel/Tools/FCE/BinaryParse.c | 1326 ++++
> > > > > > Platform/Intel/Tools/FCE/BinaryParse.h | 187 +
> > > > > > Platform/Intel/Tools/FCE/Common.c | 2183 ++++++
> > > > > > Platform/Intel/Tools/FCE/Common.h | 999 +++
> > > > > > Platform/Intel/Tools/FCE/Expression.c | 2367 ++++++
> > > > > > Platform/Intel/Tools/FCE/Fce.c | 6449
> > > > > > +++++++++++++++++
> > > > > > Platform/Intel/Tools/FCE/Fce.h | 447 ++
> > > > > > Platform/Intel/Tools/FCE/GNUmakefile | 22 +
> > > > > > Platform/Intel/Tools/FCE/IfrParse.c | 4836
> > ++++++++++++
> > > > > > Platform/Intel/Tools/FCE/IfrParse.h | 789 ++
> > > > > > Platform/Intel/Tools/FCE/Makefile | 19 +
> > > > > > .../Intel/Tools/FCE/MonotonicBasedVariable.c | 874 +++
> > > > > > .../Intel/Tools/FCE/MonotonicBasedVariable.h | 162 +
> > > > > > Platform/Intel/Tools/FCE/TimeBasedVariable.c | 878 +++
> > > > > > Platform/Intel/Tools/FCE/TimeBasedVariable.h | 166 +
> > > > > > Platform/Intel/Tools/FCE/Variable.c | 1091 +++
> > > > > > Platform/Intel/Tools/FCE/Variable.h | 154 +
> > > > > > Platform/Intel/Tools/FCE/VariableCommon.h | 55 +
> > > > > > .../Tools/FMMT/FirmwareModuleManagement.c | 2559
> > +++++++
> > > > > > .../Tools/FMMT/FirmwareModuleManagement.h | 479 ++
> > > > > > Platform/Intel/Tools/FMMT/FmmtConf.ini | 6 +
> > > > > > Platform/Intel/Tools/FMMT/FmmtLib.c | 5051
> > > > > > +++++++++++++
> > > > > > Platform/Intel/Tools/FMMT/GNUmakefile | 16 +
> > > > > > Platform/Intel/Tools/FMMT/Makefile | 17 +
> > > > > > Platform/Intel/Tools/FMMT/Rebase.c | 846 +++
> > > > > > Platform/Intel/Tools/FMMT/Rebase.h | 31 +
> > > > > > Platform/Intel/Tools/GNUmakefile | 30 +
> > > > > > Platform/Intel/Tools/Makefile | 33 +
> > > > > > Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++
> > > > > > Silicon/Intel/Tools/FitGen/FitGen.h | 48 +
> > > > > > Silicon/Intel/Tools/FitGen/GNUmakefile | 16 +
> > > > > > Silicon/Intel/Tools/FitGen/Makefile | 17 +
> > > > > > Silicon/Intel/Tools/GNUmakefile | 34 +
> > > > > > Silicon/Intel/Tools/Makefile | 31 +
> > > > > > 41 files changed, 41578 insertions(+)
> > > > > > create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > > > > > create mode 100644
> > Platform/Intel/Tools/BfmLib/BinFileManager.c
> > > > > > create mode 100644
> > Platform/Intel/Tools/BfmLib/BinFileManager.h
> > > > > > create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > > > > > create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > > > > > create mode 100644
> > > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > > > > > create mode 100644
> > > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > > > > > create mode 100644
> > Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > > > > > create mode 100644
> > Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > > > > > create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > > > > > create mode 100644
> > > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > > > > > create mode 100644
> > > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > > > > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > > > > > create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > > > > > create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > > > > > create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > > > > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > > > > > create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > > > > > create mode 100644 Platform/Intel/Tools/GNUmakefile
> > > > > > create mode 100644 Platform/Intel/Tools/Makefile
> > > > > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > > > > > create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > > > > > create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > > > > > create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > > > > > create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > > > > > create mode 100644 Silicon/Intel/Tools/Makefile
> > > > > >
> > > > > > --
> > > > > > 2.18.0.windows.1
> > > > > >
> > > > > >
> > > > > >
^ permalink raw reply [flat|nested] 15+ messages in thread