From nobody Wed May 1 07:02:20 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+42669+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+42669+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1561080413; cv=none; d=zoho.com; s=zohoarc; b=miJ3nmw5BnQ2+yYhd1qTyftkFdBzPR7X95XZrTTvtVObV0K+eQZs+vJUn7mCYZtK6DIf++5CzSDw1pHmTc7OoxqcROhHgmTWShTHxZ5wEN+ptE7hWoQWdr8aQ4uWwe49MNjBep3y+Efy8gE0VV4j4oq/1duJVdZFje9Nh1YBPs0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1561080413; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To:ARC-Authentication-Results; bh=8XHN7JAThAAwmRIs3nPxliro0eupON4Sh0uZeQ2tvRc=; b=RbzQrZUwQj6ah7dYvFME66wYFgr+iPx+D/SDH47TOiKTatcJpsBSs4aU5O+0+32bnYm4CtHUXk3esQG+tNeSQ2kP9N6OpjspsOvQdT9vCHwFbZLJHNAbFPWb77h+ZSukdQ5Bq6QWHQXzfxh+0mgwrOp1iIYL4ZGoFsvmCehOnxI= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+42669+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1561080413531842.6075362149264; Thu, 20 Jun 2019 18:26:53 -0700 (PDT) Return-Path: X-Received: from mga01.intel.com (mga01.intel.com []) by groups.io with SMTP; Thu, 20 Jun 2019 18:26:52 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 Jun 2019 18:26:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,398,1557212400"; d="scan'208";a="358723158" X-Received: from shenglei-dev.ccr.corp.intel.com ([10.239.158.52]) by fmsmga005.fm.intel.com with ESMTP; 20 Jun 2019 18:26:48 -0700 From: "Zhang, Shenglei" To: devel@edk2.groups.io Cc: Bob Feng , Liming Gao Subject: [edk2-devel] [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT Date: Fri, 21 Jun 2019 09:26:38 +0800 Message-Id: <20190621012643.9352-2-shenglei.zhang@intel.com> In-Reply-To: <20190621012643.9352-1-shenglei.zhang@intel.com> References: <20190621012643.9352-1-shenglei.zhang@intel.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,shenglei.zhang@intel.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1561080412; bh=vEKXn4CDLrAxgeYdvLFw/1SgDNp3Ol1XlZx493g4WWo=; h=Cc:Date:From:Reply-To:Subject:To; b=xC8Ye0ND4ftdKNGPNQ3fI+vpIyLNNa5nuYJaE8BxGd/z4QYyHw2IOUX1jyOCQ7WFQVh QcDIJcarReEUMn2XJKOLhTEyYdrp5VBrxpi8vDBRSZU1Avyy6WOC1NEl0LhelHcTD8jyX 2sLZ6wmLVXI2qdsAi0jVavMwsIzNDyYtgYI= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=3D1847 Cc: Bob Feng Cc: Liming Gao Signed-off-by: Shenglei Zhang --- .../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/Platfor= m/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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FirmwareModuleManagement.h" +#include "Rebase.h" +#include +#include + +CHAR8* mGuidToolDefinition =3D "FmmtConf.ini"; +extern EFI_FIRMWARE_VOLUME_HEADER *mFvHeader; +extern UINT32 mFvLength; + +// +// Store GUIDed Section guid->tool mapping +// +EFI_HANDLE mParsedGuidedSectionTools =3D 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 =3D EFI_FFS_VOLUME_TOP_FILE_GUID; +static EFI_GUID mFSPGuid =3D 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 righ= ts reserved.\n\n"); + + // + // Details Option + // + fprintf (stdout, "Options:\n"); + + // + // Command Line for View + // + fprintf (stdout, " -v \n\ + View each FV and the named files within each FV.\n"); + + // + // Command Line for Delete entire FV + // + fprintf (stdout, " -d \= n\ + Delete the entire FV in an FD binary\n"); + + // + // Command Line for Delete file from FV + // + fprintf (stdout, " -d [ = ...] \n\ + Delete a file (or files) from the firmware volume in an FD bin= ary\n"); + + // + // Command Line for Add + // + fprintf (stdout, " -a [ ...] \n\ + Add a file (or files) to the firmware volume in an FD binary\n= "); + + // + // Command Line for Replace + // + fprintf (stdout, " -r [ ...] \n\ + The replace command combines the functionality of remove and a= dd into a single operation.\n"); + + fprintf (stdout, "\nNote:\n"); + fprintf (stdout, " is the sequence of the firmware volume inclu= ded 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 =3D LibLocateFvViaFvId(FdData, FvId, &FvInFd); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Get bottom FV + // + CurrentFv =3D FdData->Fv; + while (CurrentFv->FvNext) { + CurrentFv =3D CurrentFv->FvNext; + } + if (CurrentFv->FfsNumbers > 0 && IsVtf(&CurrentFv->FfsHeader[CurrentFv->= FfsNumbers])) { + // + // Found VTF at the top of FV + // Assume 4G address + // + *BaseAddr =3D 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 =3D LibLocateFvViaFvId(FdData, FvId, &FvInFd); + if (EFI_ERROR(Status)) { + return Status; + } + + ImageSize =3D 0; + Size =3D 0; + FspFound =3D FALSE; + FspFv =3D NULL; + CurrentFv =3D FdData->Fv; + while (CurrentFv) { + if (CurrentFv->FfsNumbers > 0 && IsFsp(&CurrentFv->FfsHeader[0])) { + Offset =3D CurrentFv->ImageAddress + CurrentFv->FfsAttuibutes[0].Off= set; + CurrentFile =3D (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset); + // + // Skip FFS header + // + Offset +=3D GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)CurrentFile); + // + // Stip section header + // + Offset +=3D GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)(FdB= uffer + Offset)); + // + // We have raw FSP here, and 24 is the image size + // + ImageSize =3D *((UINT32 *)(FdBuffer + Offset + 24)); + // + // 28 is the base address + // + *BaseAddr =3D *((UINT32 *)(FdBuffer + Offset + 28)); + FspFound =3D TRUE; + FspFv =3D CurrentFv; + } + if (CurrentFv =3D=3D FvInFd){ + break; + } + CurrentFv =3D CurrentFv->FvNext; + } + if (!FspFound) { + return EFI_NOT_FOUND; + } + // + // Check if FSP binary contains this FV + // + while (FspFv !=3D NULL) { + Size +=3D FspFv->FvHeader->FvLength; + if (FspFv =3D=3D FvInFd) { + break; + } + FspFv =3D FspFv->FvNext; + } + if (Size <=3D 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 =3D EFI_FV_FILETYPE_FFS_PAD; + PadFile->Attributes =3D 0; + + // + // Write pad file size (calculated size minus next file header size) + // + if (PadFileSize >=3D MAX_FFS_SIZE) { + memset(PadFile->Size, 0, sizeof(UINT8)* 3); + ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize =3D PadFileSize; + PadFile->Attributes |=3D FFS_ATTRIB_LARGE_FILE; + hdrSize =3D sizeof(EFI_FFS_FILE_HEADER2); + } + else { + PadFile->Size[0] =3D (UINT8)(PadFileSize & 0xFF); + PadFile->Size[1] =3D (UINT8)((PadFileSize >> 8) & 0xFF); + PadFile->Size[2] =3D (UINT8)((PadFileSize >> 16) & 0xFF); + hdrSize =3D sizeof(EFI_FFS_FILE_HEADER); + } + + // + // Fill in checksums and state, they must be 0 for checksumming. + // + PadFile->IntegrityCheck.Checksum.Header =3D 0; + PadFile->IntegrityCheck.Checksum.File =3D 0; + PadFile->State =3D 0; + PadFile->IntegrityCheck.Checksum.Header =3D CalculateChecksum8((UINT8 *)= PadFile, hdrSize); + PadFile->IntegrityCheck.Checksum.File =3D FFS_FIXED_CHECKSUM; + + PadFile->State =3D EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID = | EFI_FILE_DATA_VALID; + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + PadFile->State =3D (UINT8)~(PadFile->State); + } +} + +static +UINT8* ReadFileToBuffer(CONST CHAR8 *FdName, UINT32 *FdSize) { + FILE* file; + + UINT8 *FdBuffer =3D NULL; + + file =3D fopen(FdName, "rb"); + if (file =3D=3D NULL) + return NULL; + + fseek(file, 0, SEEK_SET); + fseek(file, 0, SEEK_END); + *FdSize =3D ftell(file); + fseek(file, 0, SEEK_SET); + + FdBuffer =3D malloc(*FdSize); + if (FdBuffer =3D=3D NULL) { + goto FAIL; + } + if (fread(FdBuffer, 1, *FdSize, file) !=3D *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_F= ILE_HEADER2 *Ffs) { + EFI_FFS_FILE_HEADER2 *NextFile; + UINTN FfsSize; + UINTN FvSize; + UINTN Offset; + + FfsSize =3D GetFfsFileLength((EFI_FFS_FILE_HEADER *)Ffs); + FfsSize +=3D (UINT8 *)ALIGN_POINTER(((UINT8 *)Ffs + FfsSize), 8) - ((UIN= T8 *)Ffs + FfsSize); + FvBufGetSize(Fv, &FvSize); + Offset =3D (UINT8 *)Ffs - (UINT8 *)Fv; + if (Offset + FfsSize < FvSize) { + NextFile =3D (EFI_FFS_FILE_HEADER2 *)((UINT8 *)Ffs + FfsSize); + if (NextFile->Type =3D=3D EFI_FV_FILETYPE_FFS_PAD) { + FfsSize +=3D 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 =3D=3D NULL || Alignment =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + switch ((FfsFile->Attributes >> 3) & 0x07) { + + case 0: + // + // 1 byte alignment + // + *Alignment =3D 0; + break; + + case 1: + // + // 16 byte alignment + // + *Alignment =3D 4; + break; + + case 2: + // + // 128 byte alignment + // + *Alignment =3D 7; + break; + + case 3: + // + // 512 byte alignment + // + *Alignment =3D 9; + break; + + case 4: + // + // 1K byte alignment + // + *Alignment =3D 10; + break; + + case 5: + // + // 4K byte alignment + // + *Alignment =3D 12; + break; + + case 6: + // + // 32K byte alignment + // + *Alignment =3D 15; + break; + + case 7: + // + // 64K byte alignment + // + *Alignment =3D 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 =3D 0; + PadSize =3D 0; + Pad =3D NULL; + ReadFfsAlignment((EFI_FFS_FILE_HEADER *)InputFfs, &Align); + Align =3D 1 << Align; + HdrSize =3D GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs); + + FfsSize =3D CalcuFfsSize(Fv, OldFfs); + // + // Align data + // + if ((((UINT8 *)OldFfs - (UINT8 *)Fv) + HdrSize) % Align !=3D 0) { + PadSize =3D ((UINT8 *)OldFfs - (UINT8 *)Fv) + sizeof (EFI_FFS_FILE_HEA= DER)+HdrSize; + while (PadSize % Align !=3D 0) { + PadSize++; + } + PadSize -=3D HdrSize; + PadSize -=3D ((UINT8 *)OldFfs - (UINT8 *)Fv); + if (FfsSize < PadSize) { + return FALSE; + } + FfsSize -=3D PadSize; + Pad =3D OldFfs; + OldFfs =3D (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + PadSize); + } + + NewFileSize =3D GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs); + Offset =3D (UINT8 *)ALIGN_POINTER(((UINT8 *)OldFfs + NewFileSize), 8) - = ((UINT8 *)OldFfs + NewFileSize); + if (FfsSize >=3D NewFileSize && FfsSize - NewFileSize <=3D 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 >=3D 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 =3D (UINT8)~(InputFfs->State); + } + if (PadSize !=3D 0) { + AddPadFile(Fv, Pad, PadSize); + } + return TRUE; +} + +static + +EFI_STATUS +AddFfs(UINT8 *FdBuffer, UINT32 ImageAddress, EFI_FIRMWARE_VOLUME_HEADER* F= v, 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 =3D GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs); + + Offset =3D 0; + CurrentFile =3D NULL; + FreeOffset =3D 0; + do { + if (FreeOffset =3D=3D 0 && memcmp(FdBuffer + ImageAddress + (UINTN)ALI= GN_POINTER(Offset, 8), &FreeHeader, sizeof(EFI_FFS_FILE_HEADER)) =3D=3D 0) { + // + // Offset of free FV space found + // + FreeOffset =3D (UINTN)ALIGN_POINTER(Offset, 8); + } + Status =3D FvBufFindNextFile(FdBuffer + ImageAddress, &Offset, (VOID *= *)&CurrentFile); + if (Status =3D=3D EFI_NOT_FOUND) { + CurrentFile =3D NULL; + break; + } + else if (EFI_ERROR(Status)) { + return Status; + } + + if (CurrentFile !=3D NULL && CurrentFile->Type =3D=3D EFI_FV_FILETYPE_= FFS_PAD && + ReplaceFfs(Fv, InputFfs, CurrentFile)) { + *OffsetAdded =3D (UINT8 *)CurrentFile - (FdBuffer + ImageAddress); + return EFI_SUCCESS; + } + } while (CurrentFile !=3D NULL); + + if (FreeOffset !=3D 0) { + if (Fv->FvLength - FreeOffset < FfsSize) { + return EFI_ABORTED; + } + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + InputFfs->State =3D (UINT8)~(InputFfs->State); + } + memcpy(FdBuffer + ImageAddress + FreeOffset, InputFfs, FfsSize); + *OffsetAdded =3D FreeOffset; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +static +EFI_STATUS +FindPreviousFile(VOID *Fv, VOID *CurrentFile, VOID **PreFile) { + EFI_STATUS Status; + VOID *File =3D NULL; + UINTN Offset =3D 0; + + do { + *PreFile =3D File; + Status =3D FvBufFindNextFile(Fv, &Offset, &File); + if (Status =3D=3D EFI_NOT_FOUND) { + CurrentFile =3D NULL; + break; + } + else if (EFI_ERROR(Status)) { + return Status; + } + if (File =3D=3D CurrentFile) { + return EFI_SUCCESS; + } + } while (CurrentFile !=3D NULL); + *PreFile =3D NULL; + return Status; +} + +static +BOOLEAN +NeedNewPath(FV_INFORMATION *FvInFd, CHAR8 *FvId, UINT32 FileIndex, BOOLEAN= IsAdd) { + UINT32 Index; + + Index =3D 0; + + if (strcmp(FvId, FvInFd->FvName) !=3D 0) { + return FALSE; + } + if (IsAdd) { + return TRUE; + } + if (FvInFd->FfsAttuibutes[FileIndex].FvLevel !=3D 1) { + return FALSE; + } + + for (Index =3D 0; Index <=3D FvInFd->FfsNumbers; Index++) { + if (FvInFd->FfsAttuibutes[Index].FvLevel !=3D 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 =3D 0; + CHAR16 *UIName; + CHAR16 *FfsUIName; + UINT32 FileNumber =3D 0; + + UIName =3D (CHAR16 *)malloc(_MAX_PATH); + if (NULL =3D=3D UIName) { + return 0; + } + FfsUIName =3D (CHAR16 *)malloc(_MAX_PATH); + if (NULL =3D=3D FfsUIName) { + free(UIName); + return 0; + } + LibAscii2Unicode(File, UIName); + for (Index =3D 0; Index <=3D 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), _MA= X_PATH); + + if (FvInFd->FfsAttuibutes[Index].UiNameSize > 0 && memcmp(UIName, FfsU= IName, FvInFd->FfsAttuibutes[Index].UiNameSize) =3D=3D 0) { + FileNumber +=3D 1; + *MatchIndex =3D 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 =3D NULL; + FileNamePath =3D NULL; + +#ifndef __GNUC__ + CurDir =3D strtok (PathList,";"); +#else + CurDir =3D strtok (PathList,":"); +#endif + while (CurDir !=3D NULL) { + FileNamePath =3D (char *)calloc( + strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileNa= me) + 1, + sizeof(char) + ); + if (FileNamePath =3D=3D NULL) { + return NULL; + } + sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName); + if (access (FileNamePath, 0) !=3D -1) { + return FileNamePath; + } +#ifndef __GNUC__ + CurDir =3D strtok(NULL, ";"); +#else + CurDir =3D strtok(NULL, ":"); +#endif + free (FileNamePath); + FileNamePath =3D NULL; + } + return NULL; +} + +UINT32 lenList(FILENode* head){ + FILENode *p =3D head; + UINT32 sum=3D0; + if(head=3D=3DNULL) return 0; + while(p!=3DNULL){ + sum+=3D1; + p=3Dp->Next; + } + return sum; +} + +void sortList(FILENode* head){ + UINT32 len =3D lenList(head); + FILENode *p =3D head; + UINT32 i; + UINT32 j; + if(len=3D=3D0) return; + for(i=3D1; iSubLevel < p->Next->SubLevel){ + CHAR8 *FileName =3D p->FileName; + UINT8 tmp =3D p->SubLevel; + p->SubLevel =3D p->Next->SubLevel; + p->Next->SubLevel =3D tmp; + p->FileName =3D p->Next->FileName; + p->Next->FileName =3D FileName; + } + p=3Dp->Next; + } + } +} + +BOOLEAN +ParseSection ( + IN EFI_FFS_FILE_HEADER2 *InputFfs +) +{ + BOOLEAN UISectionFlag; + UINT32 SectionLength; + UINT32 ParsedLength; + UINT32 FfsFileSize; + UINT8 *Ptr; + EFI_SECTION_TYPE Type; + + UISectionFlag =3D FALSE; + Ptr =3D NULL; + SectionLength =3D 0; + ParsedLength =3D GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputF= fs); + FfsFileSize =3D GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs= ); + + while (ParsedLength < FfsFileSize) { + Ptr =3D (UINT8 *)InputFfs + ParsedLength; + SectionLength =3D GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size= ); + Type =3D ((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 se= ction + // header worth of 0xFF bytes. + // + if ((SectionLength =3D=3D 0xffffff) && (Type =3D=3D 0xff)) { + ParsedLength +=3D 4; + continue; + } + if (Type =3D=3D EFI_SECTION_USER_INTERFACE) { + UISectionFlag =3D TRUE; + break; + } + ParsedLength +=3D SectionLength; + // + // We make then next section begin on a 4-byte boundary + // + ParsedLength =3D GetOccupiedSize (ParsedLength, 4); + } + return UISectionFlag; + +} + + +/** + + Show the FD image layout information. Only display the modules with UI n= ame. + + @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 =3D NULL; + CurrentFv =3D NULL; + FvImage =3D NULL; + TemDir =3D NULL; + FvSize =3D 0; + BytesRead =3D 0; + FfsCount =3D 0; + FvCount =3D 0; + ErrorStatus =3D EFI_SUCCESS; + + // + // Check the FD file name/path. + // + if (FdInName =3D=3D NULL) { + Error("FMMT", 0, 1001, "Invalid parameter! Please specify ", FdInName); + Usage(); + return EFI_INVALID_PARAMETER; + } + + // + // Open the file containing the FV + // + InputFile =3D fopen (FdInName, "rb"); + if (InputFile =3D=3D NULL) { + Error (NULL, 0, 0001, "Error opening the input file", FdInName); + return EFI_INVALID_PARAMETER; + } + + Status =3D LibFindFvInFd (InputFile, &LocalFdData); + + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 1001, "Error while search FV in FD", ""); + fclose (InputFile); + return EFI_ABORTED; + } + + CurrentFv =3D LocalFdData->Fv; + + + do { + + memset (CurrentFv->FvName, '\0', _MAX_PATH); + + if (FvCount =3D=3D 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) !=3D 0) { + Error (NULL, 0, 0003, "error parsing FV image", "%s FD file is inval= id", InputFile); + fclose (InputFile); + ErrorStatus =3D EFI_ABORTED; + goto Done; + } + + Status =3D LibGetFvSize(InputFile, &FvSize); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invali= d", InputFile); + fclose (InputFile); + ErrorStatus =3D EFI_ABORTED; + goto Done; + } + + // + // Seek to the start of the image, then read the entire FV to the buff= er + // + fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET); + + + FvImage =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize); + + if (FvImage =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + fclose (InputFile); + ErrorStatus =3D EFI_ABORTED; + goto Done; + } + + BytesRead =3D fread (FvImage, 1, FvSize, InputFile); + if ((unsigned int) BytesRead !=3D FvSize) { + Error ("FMMT", 0, 0004, "error reading FvImage from", FdInName); + free (FvImage); + fclose (InputFile); + ErrorStatus =3D EFI_ABORTED; + goto Done; + } + + // + // Collect FV information each by each. + // + Status =3D LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &CurrentFv->En= capData, &FfsCount, &FvCount, ViewFlag, FALSE); + if (FvImage !=3D NULL) { + free (FvImage); + FvImage =3D NULL; + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while get information from FV %s", Fv= Name); + ErrorStatus =3D 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 !=3D NULL) && ((CurrentFv->FvName) !=3D NULL) && !strcmp= (CurrentFv->FvName, FvName)) { + fclose (InputFile); + ErrorStatus =3D EFI_ABORTED; + goto Done; + } + } + + + FfsCount =3D 0; + + CurrentFv =3D CurrentFv->FvNext; + + } while (CurrentFv !=3D NULL); + + fclose (InputFile); + + if (ViewFlag) { + + TemDir =3D getcwd (NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _M= AX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + ErrorStatus =3D 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 =3D LibRmDir (TemDir); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "remove = directory failed!"); + ErrorStatus =3D Status; + } + } +Done: + if (!ViewFlag) { + *FdData =3D 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 =3D FALSE; + Index =3D 0; + EndId =3D 0; + NewFvLength =3D 0; + FvNumInFd =3D 0; + FvNumInFdCounter =3D 0; + NewAddedFfsLevel =3D 0; + FdData =3D NULL; + FvInFd =3D NULL; + NewFdFile =3D NULL; + NewFvFile =3D NULL; + Buffer =3D NULL; + TemDir =3D NULL; + OutputFileName =3D NULL; + FvId =3D NULL; + NewFile =3D NULL; + + FdBuffer =3D NULL; + InputFfs =3D NULL; + BaseAddr =3D 0; + OffsetAdded =3D 0; + FdSize =3D 0; + + for (i =3D 0; i < count; i ++){ + tmp =3D FileList + i; + FvId =3D tmp->FvId; + FdData =3D tmp->FdData; + if (FdData =3D=3D NULL) { + Status =3D FmmtImageView (FdInName, FvId, FALSE, &FdData); + if (EFI_ERROR (Status) && Status !=3D EFI_UNSUPPORTED) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", "G= athering FD information failed!"); + return Status; + } + if (FdData =3D=3D NULL) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", ""= ); + return EFI_ABORTED; + } + + Status =3D LibLocateFvViaFvId (FdData, FvId, &FvInFd); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0005, "error while locate FV in FD", ""); + return Status; + } + (FileList + i) -> FdData =3D FdData; + (FileList + i) -> FvInFd =3D FvInFd; + (FileList + i) -> FvLevel =3D FvInFd -> FvLevel; + } + } + + for (i =3D 0; i < count; i++) { + for (j =3D i + 1; j < count; j++){ + if (((FileList + i)->FvId =3D=3D NULL) || ((FileList + j)->FvId = =3D=3D NULL)) { + continue; + } + if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) = =3D=3D 0){ + NewFileNode =3D (FileList + j)->NewFile; + while (NewFileNode ->Next !=3D NULL) { + NewFileNode =3D NewFileNode->Next; + } + NewFileNode->Next =3D (FileList + i)->NewFile; + (FileList + i)->FvId =3D NULL; + } + } + } + + for (i =3D 0; i < count; i ++){ + if ((FileList + i)->FvId =3D=3D NULL) { + continue; + } + sortList ((FileList + i)-> NewFile); + } + + TemDir =3D getcwd(NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _M= AX_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 =3D=3D NULL) { + FdBuffer =3D ReadFileToBuffer(FdInName, &FdSize); + if (FdBuffer =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while adding file", "cannot read= input file."); + return EFI_ABORTED; + } + } + + for (i =3D 0; i < count; i ++){ + tmp =3D FileList + i; + FvId =3D tmp->FvId; + if (FvId =3D=3D NULL) { + continue; + } + FdData =3D tmp->FdData; + FvInFd =3D tmp->FvInFd; + NewFileNode =3Dtmp->NewFile; + + NewFile =3D NewFileNode->FileName; + InputFfs =3D (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &Ne= wFileSize); + if (InputFfs =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while adding file", "cannot read= input file."); + Status =3D EFI_ABORTED; + goto FAILED; + } + HasUISection =3D FALSE; + HasUISection =3D ParseSection(InputFfs); + if (!HasUISection) { + printf ("WARNING: The newly add file must have a user interfac= e (UI) section, otherwise it cannot be deleted or replaced. \n"); + } + if (NeedNewPath(FvInFd, FvId, 0, TRUE)) { + do { + NewFile =3D NewFileNode->FileName; + // + // TODO: currently only root FV is handled + // + InputFfs =3D (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewF= ile, &NewFileSize); + if (InputFfs =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while adding file", "can= not read input file."); + Status =3D EFI_ABORTED; + goto FAILED; + } + + Fv =3D (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->I= mageAddress); + + Status =3D AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, Inpu= tFfs, &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 =3D=3D EFI_FV_FILETYPE_PEIM || InputFfs= ->Type =3D=3D EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + Status =3D GetBaseAddrFromFsp(FdData, FdBuffer, FvId, = &BaseAddr); + if (!EFI_ERROR(Status)) { + mFvHeader =3D FvInFd->FvHeader; + mFvLength =3D (UINT32)FvInFd->FvHeader->FvLength; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER = *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + else { + Status =3D GetBaseAddrFromVtf(FdData, FvId, &BaseA= ddr); + if (!EFI_ERROR(Status)) { + mFvHeader =3D FvInFd->FvHeader; + mFvLength =3D (UINT32)FvInFd->FvHeader->FvLeng= th; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEA= DER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + } + } + NewFileNode =3D NewFileNode->Next; + free (InputFfs); + InputFfs =3D NULL; + } while (NewFileNode !=3D NULL); + } else { + do { + NewFile =3D NewFileNode->FileName; + if (strlen (NewFile) > _MAX_PATH - 1) { + Error ("FMMT", 0, 2000, "error while adding file", "New = file name is too long!"); + Status =3D EFI_ABORTED; + goto FAILED; + } + FvNumInFd =3D ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd-= >FvName + 2)); + if (FvInFd->FfsNumbers =3D=3D 0) { + NewAddedFfsLevel =3D FvInFd->FfsAttuibutes[0].Level; + } + for (Index =3D 0; Index <=3D FvInFd->FfsNumbers; Index++) { + if (FvInFd->FfsAttuibutes[Index].IsFvStart =3D=3D 1) { + FvNumInFdCounter++; + } + if ( FvNumInFdCounter =3D=3D FvNumInFd && FvInFd->FfsA= ttuibutes[Index].IsFvEnd =3D=3D 1) { + NewAddedFfsLevel =3D FvInFd->FfsAttuibutes[Index].= Level; + EndId =3D Index+1; + break; + } + if (FvInFd->FfsAttuibutes[Index].IsFvEnd =3D=3D 1) { + FvNumInFdCounter--; + if (FvNumInFdCounter =3D=3D 0) { + FvNumInFd--; + } + } + } + + // + // Add the new file into FV. + // + FvInFd->FfsNumbers +=3D 1; + for (Index =3D FvInFd->FfsNumbers; Index > EndId; Index--)= { + FvInFd->FfsAttuibutes[Index] =3D FvInFd->FfsAttuibutes= [Index - 1]; + } + strncpy(FvInFd->FfsAttuibutes[EndId].FfsName, NewFile, _MA= X_PATH - 1); + FvInFd->FfsAttuibutes[EndId].FfsName[_MAX_PATH - 1] =3D 0; + FvInFd->FfsAttuibutes[EndId].Level =3D NewAddedFfsLevel; + memset (&FvInFd->FfsAttuibutes[EndId].GuidName, '\0', size= of(EFI_GUID)); + if (EndId > 0) { + FvInFd->FfsAttuibutes[EndId].FvLevel =3D FvInFd->FfsAt= tuibutes[EndId - 1].FvLevel; + FvInFd->FfsAttuibutes[EndId - 1].IsFvEnd =3D 0; + } + FvInFd->FfsAttuibutes[EndId].IsFvEnd =3D 1; + FvInFd->FfsAttuibutes[EndId].IsFvStart =3D 0; + NewFileNode =3D NewFileNode->Next; + } while (NewFileNode !=3D NULL); + + mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO); + + Status =3D LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &Output= FileName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image"= , "Make new FV file failed!"); + goto FAILED; + } + + NewFvFile =3D fopen (OutputFileName->FFSName, "rb+"); + if (NewFvFile =3D=3D NULL) { + Error ("FMMT", 0, 0003, "error Open FV file", "cannot Crea= te a new FD file."); + Status =3D EFI_ABORTED; + goto FAILED; + } + + fseek(NewFvFile,0,SEEK_SET); + fseek(NewFvFile,0,SEEK_END); + + NewFvLength =3D ftell(NewFvFile); + fseek(NewFvFile,0,SEEK_SET); + Buffer =3D malloc ((size_t)NewFvLength); + if (Buffer =3D=3D NULL) { + Status =3D EFI_ABORTED; + fclose(NewFvFile); + goto FAILED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) !=3D (s= ize_t) NewFvLength) { + Error ("FMMT", 0, 0003, "error reading FV file %s", Output= FileName->FFSName); + free (Buffer); + Status =3D EFI_ABORTED; + fclose(NewFvFile); + goto FAILED; + } + + if (NewFvLength <=3D FvInFd->FvHeader->FvLength) { + memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFv= Length); + } else { + Error ("FMMT", 0, 0004, "error writing FD file", "The add = ffs file is too large."); + } + fclose(NewFvFile); + free(Buffer); + } + } + + Status =3D LibRmDir(TemDir); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove= directory failed!"); + goto FAILED; + } + + NewFdFile =3D fopen(FdOutName, "wb"); + if (NewFdFile =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot= open target FD file!"); + Status =3D 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 !=3D NULL) { + free(FdBuffer); + } + if (InputFfs !=3D 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 =3D NULL; + UINT8 *FdBak =3D NULL; + UINT32 FdSize =3D 0; + + FIRMWARE_DEVICE *FdData =3D NULL; + + TemDir =3D 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 =3D FmmtImageView(FdInName, NULL, FALSE, &FdData); + if (EFI_ERROR(Status) && Status !=3D EFI_UNSUPPORTED) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD i= nformation failed!"); + goto END; + } + if (FdData =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while parsing FD Image", ""); + Status =3D EFI_ABORTED; + goto END; + } + + FvInFd =3D FdData->Fv; + while (FvInFd) { + if (FvInFd->FvUiName && strcmp(FvInFd->FvUiName, FvName) =3D=3D 0) { + break; + } + FvInFd =3D FvInFd->FvNext; + } + if (!FvInFd) { + Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot find th= is FV!"); + Status =3D EFI_ABORTED; + goto END; + } + FdBuffer =3D ReadFileToBuffer(FdInName, &FdSize); + FdBak =3D FdBuffer; + if (FdBuffer =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot read FD= file!"); + Status =3D EFI_ABORTED; + goto END; + } + + if (FvInFd->ImageAddress =3D=3D 0) { + FdBuffer =3D FdBuffer + FvInFd->FvHeader->FvLength; + FdSize -=3D (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 =3D fopen(FdOutName, "wb"); + if (NewFdFile =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot open ta= rget FD file!"); + Status =3D EFI_ABORTED; + goto END; + } + fwrite(FdBuffer, 1, FdSize, NewFdFile); + fclose(NewFdFile); + + Status =3D LibRmDir(TemDir); + + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while deleting root FV", "remove directo= ry 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 =3D 0; + Index =3D 0; + NewFvLength =3D 0; + FfsFoundFlag =3D 0; + FdData =3D NULL; + FvInFd =3D NULL; + OutputFileName =3D NULL; + NewFdFile =3D NULL; + NewFvFile =3D NULL; + Buffer =3D NULL; + TemDir =3D NULL; + FvNumInFd =3D 0; + Offset =3D 0; + FdBuffer =3D NULL; + + for (i =3D 0; i < count; i ++){ + tmp =3D FileList + i; + FvId =3D tmp->FvId; + FdData =3D tmp->FdData; + if (FdData =3D=3D NULL) { + Status =3D FmmtImageView (FdInName, FvId, FALSE, &FdData); + if (EFI_ERROR (Status) && Status !=3D EFI_UNSUPPORTED) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", "G= athering FD information failed!"); + return Status; + } + if (FdData =3D=3D NULL) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", ""= ); + return EFI_ABORTED; + } + + Status =3D LibLocateFvViaFvId (FdData, FvId, &FvInFd); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0005, "error while locate FV in FD", ""); + return Status; + } + (FileList + i) -> FdData =3D FdData; + (FileList + i) -> FvInFd =3D FvInFd; + (FileList + i) -> FvLevel =3D FvInFd -> FvLevel; + } + FvNumInFd =3D ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName = + 2)) + 1; + OldFileNode =3D tmp-> OldFile; + do { + DelFile =3D OldFileNode->FileName; + if (FvInFd =3D=3D NULL) { + break; + } + FfsFoundFlag =3D 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 =3D FvInFd -> FfsAttuibutes[Index].Lev= el; + OldFileNode =3D OldFileNode->Next; + } while (OldFileNode !=3D NULL); + } + + for (i =3D 0; i < count; i++) { + for (j =3D i + 1; j < count; j++) + { + if (((FileList + i)->FvId =3D=3D NULL) || ((FileList + j)->FvI= d =3D=3D NULL)) { + continue; + } + if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvNam= e) =3D=3D 0){ + OldFileNode =3D (FileList + j)->OldFile; + while (OldFileNode ->Next !=3D NULL) { + OldFileNode =3D OldFileNode->Next; + } + OldFileNode->Next =3D (FileList + i)->OldFile; + (FileList + i)->FvId =3D NULL; + } + } + } + + for (i =3D 0; i < count; i ++){ + if ((FileList + i)->FvId =3D=3D NULL) { + continue; + } + sortList ((FileList + i)-> OldFile); + } + + TemDir =3D getcwd(NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _M= AX_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 =3D=3D NULL) { + FdBuffer =3D ReadFileToBuffer(FdInName, &FdSize); + if (FdBuffer =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while deleting file", "cannot re= ad input file."); + return EFI_ABORTED; + } + } + + for (i =3D 0; i < count; i ++){ + tmp =3D FileList + i; + FvId =3D tmp->FvId; + if (FvId =3D=3D NULL) { + continue; + } + FdData =3D tmp->FdData; + FvInFd =3D tmp->FvInFd; + FvNumInFd =3D ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName = + 2)) + 1; + OldFileNode =3D tmp->OldFile; + DelFile =3D OldFileNode -> FileName; + FfsFoundFlag =3D FindFile(FvInFd, FvNumInFd, DelFile, &Index); + if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) { + do { + DelFile =3D OldFileNode -> FileName; + FfsFoundFlag =3D FindFile(FvInFd, FvNumInFd, DelFile, &Ind= ex); + // + // TODO: currently only root FV is handled + // + Offset =3D FvInFd->ImageAddress + FvInFd->FfsAttuibutes[In= dex].Offset; + if (FdBuffer !=3D NULL) { + CurrentFile =3D (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offs= et); + + FfsSize =3D CalcuFfsSize((EFI_FIRMWARE_VOLUME_HEADER *)(= FdBuffer + FvInFd->ImageAddress), CurrentFile); + + FindPreviousFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer= + FvInFd->ImageAddress), CurrentFile, (VOID **) &PreFile); + if (PreFile !=3D NULL && PreFile->Type =3D=3D EFI_FV_FIL= ETYPE_FFS_PAD) { + FfsSize +=3D (UINT8 *)CurrentFile - (UINT8 *)PreFile; + CurrentFile =3D PreFile; + } + AddPadFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvI= nFd->ImageAddress), CurrentFile, FfsSize); + } + OldFileNode =3D OldFileNode -> Next; + } while (OldFileNode !=3D NULL); + } else { + do { + DelFile =3D OldFileNode -> FileName; + FfsFoundFlag =3D FindFile(FvInFd, FvNumInFd, DelFile, &Ind= ex); + + if (FfsFoundFlag) { + // + // Delete this FFS file from Current FV structure. + // + Status =3D LibFmmtDeleteFile (FvInFd->FfsAttuibutes[In= dex].FfsName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate F= D 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', _MA= X_PATH); + FvInFd->FfsAttuibutes[Index].Level =3D 0xFF; + + // + // Since we can avoid to add NULL ffs file, at this ti= me we don't need to decrease the FFS number. + // If decrease operation executed, we should adjust th= e ffs list. It will bring in more complex. + // + //FvInFd->FfsNumbers -=3D 1; + memset(FvInFd->FfsAttuibutes[Index].UiName, '\0', _MAX= _PATH); + if (FvInFd->FfsAttuibutes[Index].FvLevel > 1) { + for (j =3D Index - 1; j >=3D 0; j--) { + if (FvInFd->FfsAttuibutes[j].FvLevel =3D=3D FvI= nFd->FfsAttuibutes[Index].FvLevel - 1) { + break; + } + } + if (Index+1 <=3D FvInFd->FfsNumbers) { + if (FvInFd->FfsAttuibutes[Index+1].FvLevel =3D= =3D FvInFd->FfsAttuibutes[Index].FvLevel + 1) { + for (j =3D Index+1; j <=3D (signed)FvInFd->Ff= sNumbers; j++) { + if (FvInFd->FfsAttuibutes[j].FvLevel > FvI= nFd->FfsAttuibutes[Index].FvLevel) { + Status =3D LibFmmtDeleteFile(FvInFd->Ff= sAttuibutes[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 =3D 0xFF; + } + } + } + } + } + } else { + printf ("Could not found the FFS file from FD!, file n= ame: %s\n", DelFile); + Status =3D EFI_ABORTED; + goto FAILED; + } + OldFileNode =3D OldFileNode -> Next; + + }while (OldFileNode !=3D NULL); + + mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO); + + Status =3D LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &Output= FileName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image"= , "Make new FV file failed!"); + goto FAILED; + } + + NewFvFile =3D fopen (OutputFileName->FFSName, "rb+"); + if (NewFvFile =3D=3D NULL) { + Error ("FMMT", 0, 0003, "error Open FV file", "cannot Crea= te a new FD file."); + Status =3D EFI_ABORTED; + goto FAILED; + } + + fseek(NewFvFile,0,SEEK_SET); + fseek(NewFvFile,0,SEEK_END); + + NewFvLength =3D ftell(NewFvFile); + fseek(NewFvFile,0,SEEK_SET); + Buffer =3D malloc ((size_t)NewFvLength); + if (Buffer =3D=3D NULL) { + fclose(NewFvFile); + Status =3D EFI_ABORTED; + goto FAILED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) !=3D (s= ize_t) NewFvLength) { + Error ("FMMT", 0, 0003, "error reading FV file %s", Output= FileName->FFSName); + fclose(NewFvFile); + free(Buffer); + Status =3D EFI_ABORTED; + goto FAILED; + } + memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLeng= th); + free(Buffer); + fclose(NewFvFile); + } + } + + Status =3D LibRmDir(TemDir); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove= directory failed!"); + goto FAILED; + } + + NewFdFile =3D fopen(FdOutName, "wb"); + if (NewFdFile =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot o= pen target FD file!"); + Status =3D 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 =3D FALSE; + Index =3D 0; + NewFvLength =3D 0; + FfsFoundFlag =3D 0; + FdData =3D NULL; + FvInFd =3D NULL; + OutputFileName =3D NULL; + NewFdFile =3D NULL; + NewFvFile =3D NULL; + Buffer =3D NULL; + TemDir =3D NULL; + Offset =3D 0; + FdBuffer =3D NULL; + InputFfs =3D NULL; + BaseAddr =3D 0; + OffsetAdded =3D 0; + FdSize =3D 0; + + for (i =3D 0; i < count; i ++){ + tmp =3D FileList + i; + FvId =3D tmp->FvId; + FdData =3D tmp->FdData; + if (FdData =3D=3D NULL){ + Status =3D FmmtImageView(FdInName, FvId, FALSE, &FdData); + if (EFI_ERROR(Status) && Status !=3D EFI_UNSUPPORTED) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Ga= thering information failed!"); + return Status; + } + + if (FdData =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while parsing FD Image", ""); + return EFI_ABORTED; + } + + Status =3D LibLocateFvViaFvId(FdData, FvId, &FvInFd); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0005, "error while locate FV in FD", ""); + return Status; + } + (FileList + i) -> FdData =3D FdData; + (FileList + i) -> FvInFd =3D FvInFd; + (FileList + i) -> FvLevel =3D FvInFd -> FvLevel; + } + FvNumInFd =3D ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName = + 2)) + 1; + OldFileNode =3D tmp-> OldFile; + NewFileNode =3D tmp-> NewFile; + do { + OldFile =3D OldFileNode -> FileName; + NewFile =3D NewFileNode -> FileName; + if (FvInFd =3D=3D NULL) { + break; + } + FfsFoundFlag =3D 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 =3D FvInFd -> FfsAttuibutes[Index].Lev= el; + NewFileNode -> SubLevel =3D FvInFd -> FfsAttuibutes[Index].Lev= el; + OldFileNode =3D OldFileNode->Next; + NewFileNode =3D NewFileNode->Next; + } while (OldFileNode !=3D NULL && NewFileNode !=3D NULL); + } + + for (i =3D 0; i < count; i++) { + for (j =3D i + 1; j < count; j++) + { + if (((FileList + i)->FvId =3D=3D NULL) || ((FileList + j)->FvI= d =3D=3D NULL)) { + continue; + } + if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvNam= e) =3D=3D 0){ + OldFileNode =3D (FileList + j)->OldFile; + NewFileNode =3D (FileList + j)->NewFile; + while (OldFileNode->Next !=3D NULL && NewFileNode->Next != =3D NULL) { + OldFileNode =3D OldFileNode->Next; + NewFileNode =3D NewFileNode->Next; + } + OldFileNode->Next =3D (FileList + i)->OldFile; + NewFileNode->Next =3D (FileList + i)->NewFile; + (FileList + i)->FvId =3D NULL; + } + } + } + + for (i =3D 0; i < count; i ++){ + if ((FileList + i)->FvId =3D=3D NULL) { + continue; + } + sortList ((FileList + i)-> OldFile); + sortList ((FileList + i)-> NewFile); + } + TemDir =3D getcwd (NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _M= AX_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 =3D=3D NULL) { + FdBuffer =3D ReadFileToBuffer(FdInName, &FdSize); + if (FdBuffer =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "cannot rea= d input file."); + return EFI_ABORTED; + } + } + + for (i =3D 0; i < count; i ++){ + tmp =3D FileList + i; + FvId =3D tmp->FvId; + if (FvId =3D=3D NULL) { + continue; + } + FdData =3D tmp->FdData; + FvInFd =3D tmp->FvInFd; + FvNumInFd =3D ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName = + 2)) + 1; + OldFileNode =3D tmp-> OldFile; + OldFile =3D OldFileNode -> FileName; + NewFileNode =3D tmp-> NewFile; + FfsFoundFlag =3D FindFile(FvInFd, FvNumInFd, OldFile, &Index); + + NewFile =3D NewFileNode->FileName; + InputFfs =3D (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &Ne= wFileSize); + if (InputFfs =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "cannot r= ead input file."); + free (FdBuffer); + return EFI_ABORTED; + } + HasUISection =3D FALSE; + HasUISection =3D ParseSection(InputFfs); + if (!HasUISection) { + printf ("WARNING: The newly replace file must have a user inte= rface (UI) section, otherwise it cannot be deleted or replaced. \n"); + } + if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) { + do { + OldFile =3D OldFileNode -> FileName; + NewFile =3D NewFileNode -> FileName; + FfsFoundFlag =3D FindFile(FvInFd, FvNumInFd, OldFile, &Ind= ex); + // + // TODO: currently only root FV is handled + // + InputFfs =3D (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewF= ile, &NewFileSize); + if (InputFfs =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "= cannot read input file."); + free (FdBuffer); + return EFI_ABORTED; + } + + Offset =3D FvInFd->ImageAddress + FvInFd->FfsAttuibutes[In= dex].Offset; + Fv =3D (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->I= mageAddress); + OffsetAdded =3D FvInFd->FfsAttuibutes[Index].Offset; + + if (!ReplaceFfs(Fv, InputFfs, (EFI_FFS_FILE_HEADER2 *)(FdB= uffer + Offset))) { + Status =3D AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, In= putFfs, &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 =3D (EFI_FFS_FILE_HEADER2 *)(FdBuffer + FvIn= Fd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset); + PadFileSize =3D CalcuFfsSize(Fv, CurrentFile); + AddPadFile(Fv, CurrentFile, PadFileSize); + } + + // + // Calculate base address of Current FV + // + if (InputFfs->Type =3D=3D EFI_FV_FILETYPE_PEIM || InputFfs= ->Type =3D=3D EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + Status =3D GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &B= aseAddr); + if (!EFI_ERROR(Status)) { + mFvHeader =3D FvInFd->FvHeader; + mFvLength =3D (UINT32)FvInFd->FvHeader->FvLength; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(F= dBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + else { + Status =3D GetBaseAddrFromVtf(FdData, FvId, &BaseAddr); + if (!EFI_ERROR(Status)) { + mFvHeader =3D FvInFd->FvHeader; + mFvLength =3D (UINT32)FvInFd->FvHeader->FvLength; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)= (FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + } + } + OldFileNode =3D OldFileNode -> Next; + NewFileNode =3D NewFileNode -> Next; + free (InputFfs); + InputFfs =3D NULL; + } while (OldFileNode !=3D NULL && NewFileNode!=3D NULL); + } else { + do { + OldFile =3D OldFileNode->FileName; + NewFile =3D NewFileNode->FileName; + FfsFoundFlag =3D FindFile(FvInFd, FvNumInFd, OldFile, &Ind= ex); + // + // Replace this FFS file with the new one. + // + if (strlen (NewFile) > _MAX_PATH - 1) { + Error ("FMMT", 0, 2000, "error while replacing file", "N= ew file name is too long!"); + free (FdBuffer); + return EFI_ABORTED; + } + strncpy(FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MA= X_PATH - 1); + FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] =3D 0; + OldFileNode =3D OldFileNode->Next; + NewFileNode =3D NewFileNode->Next; + } while (OldFileNode !=3D NULL && NewFileNode !=3D NULL); + Status =3D LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &Output= FileName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image"= , "Make new FV file failed!"); + free (FdBuffer); + return Status; + } + + NewFvFile =3D fopen (OutputFileName->FFSName, "rb+"); + if (NewFvFile =3D=3D NULL) { + Error ("FMMT", 0, 0003, "error Open FV file", "cannot Crea= te a new FD file."); + free (FdBuffer); + return EFI_ABORTED; + } + + fseek(NewFvFile,0,SEEK_SET); + fseek(NewFvFile,0,SEEK_END); + + NewFvLength =3D ftell(NewFvFile); + fseek(NewFvFile,0,SEEK_SET); + Buffer =3D malloc ((size_t)NewFvLength); + if (Buffer =3D=3D NULL) { + fclose(NewFvFile); + free (FdBuffer); + return EFI_ABORTED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) !=3D (s= ize_t) NewFvLength) { + Error ("FMMT", 0, 0003, "error reading FV file %s", Output= FileName->FFSName); + free(Buffer); + free (FdBuffer); + fclose(NewFvFile); + return EFI_ABORTED; + } + if (NewFvLength <=3D FvInFd->FvHeader->FvLength) { + memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFv= Length); + }else { + Error ("FMMT", 0, 0004, "error writing FD file", "The repl= ace ffs file is too large."); + } + free(Buffer); + fclose(NewFvFile); + } + } + + Status =3D LibRmDir(TemDir); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove d= irectory failed!"); + } + + NewFdFile =3D fopen(FdOutName, "wb"); + if (NewFdFile =3D=3D NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "Cannot open ta= rget FD file!"); + Status =3D 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 !=3D NULL) { + free(FdBuffer); + } + if (InputFfs !=3D 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 =3D NULL; + q =3D NULL; + TemDir =3D NULL; + CheckFileExist =3D NULL; + PathList =3D NULL; + NewPathList =3D NULL; + EnvLen =3D 0; + count =3D 0; + exist =3D -1; + + TemDir =3D 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 <=3D 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[] =3D "/tmp/fileXXXXXX"; + UINTN Fdtmp; + Fdtmp =3D mkstemp(tmp); + close(Fdtmp); +#endif + + // + // Save, skip filename arg + // + FileName =3D 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", N= ULL); + return 1; + } + strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1); + FullGuidToolDefinition[_MAX_PATH - 1] =3D 0; + FileNameIndex =3D strlen (FullGuidToolDefinition); + while (FileNameIndex !=3D 0) { + FileNameIndex --; + if (FullGuidToolDefinition[FileNameIndex] =3D=3D OS_SEP) { + FullGuidToolDefinition[FileNameIndex] =3D 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 =3D getenv("PATH"); + if (PathList =3D=3D NULL) { + Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not ex= ist", NULL); + return 1; + } + EnvLen =3D strlen(PathList); + NewPathList =3D (char *)calloc( + strlen (".") + + strlen (";") + + strlen (FullGuidToolDefinition) + + strlen (";") + + EnvLen + + 1, + sizeof(char) + ); + if (NewPathList =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + PathList =3D NULL; + free (PathList); + return 1; + } +#ifndef __GNUC__ + sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList); +#else + sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList); +#endif + PathList =3D NULL; + free (PathList); + + // + // Load Guid Tools definition + // + InFilePath =3D SearchConfigFromPathList(NewPathList, mGuidToolDefinition= ); + free (NewPathList); + if (InFilePath !=3D NULL) { + printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePa= th); + mParsedGuidedSectionTools =3D ParseGuidedSectionToolsFile (InFilePath); + free (InFilePath); + } else { + // + // Use the pre-defined standard guided tools. + // + printf ("\nThe Guid Tool Definition comes from the build-in default conf= iguration. \n"); + mParsedGuidedSectionTools =3D LibPreDefinedGuidedTools (); + } + + if ((strcmp(Argv[0], "-v") =3D=3D 0) || (strcmp(Argv[0], "-V") =3D=3D 0)= ) { + // + // View the FD binary image information. + // + if (Argc <=3D 1) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the para= meter is correct.", ""); + Usage (); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist =3D fopen (Argv[1], "rb"); + if (CheckFileExist =3D=3D NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please= make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + Status =3D 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") =3D=3D 0) || (strcmp(Argv[0], "-D") = =3D=3D 0)) { + // + // Delete some named FFS file from FD binary image. + // + if (!((Argc =3D=3D 4) || ((Argc - 3) % 2 =3D=3D 0))) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the par= ameter is correct.", ""); + Usage (); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist =3D fopen (Argv[1], "rb"); + if (CheckFileExist =3D=3D NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please= make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + if ((Argc - 3) % 2 =3D=3D 0) { + FileData =3D malloc(sizeof (Data) * (Argc - 3)/2); + if (FileData =3D=3D NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", N= ULL); + return 1; + } + for(index =3D 0; index < (Argc - 3)/2; index ++) { + p =3D malloc(sizeof (FILENode)); + if (p =3D=3D NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated= ", NULL); + free (FileData); + return 1; + } + p -> FileName =3D Argv[3 + index * 2]; + p -> SubLevel =3D 0; + exist =3D -1; + for (j =3D 0; j < count; j ++) { + if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) = =3D=3D 0)) { + exist =3D j; + break; + } + } + if (exist >=3D 0) { + p -> Next =3D (FileData + j) -> OldFile; + (FileData + j) -> OldFile =3D p; + } else { + (FileData + count) -> NewFile =3D NULL; + (FileData + count) -> FdData =3D NULL; + (FileData + count) -> FvLevel =3D 0; + (FileData + count) -> FvInFd =3D NULL; + (FileData + count) -> FvId =3D Argv[2 + index * 2];; + (FileData + count) -> OldFile =3D p; + p -> Next =3D NULL; + count ++; + } + } + + if (count <=3D 0) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gather= ing information failed!"); + } + for (index =3D 0; index < count; index ++) { + for (j =3D index + 1; j < count; j ++) { + if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId= ) < 0)) { + CHAR8 *tmp =3D (FileData + index)->FvId; + FILENode *t =3D (FileData + index)->OldFile; + (FileData + index)->FvId =3D (FileData + j)->FvId; + (FileData + index)-> OldFile =3D (FileData + j)->OldFi= le; + (FileData + j)-> OldFile =3D t; + (FileData + j)-> FvId =3D tmp; + } + } + } + + // + // Delete some FFS file + // + Status =3D FmmtImageDelete(Argv[1], FileData, count, Argv[Argc-1]); + for (index =3D 0; index < count; index ++) { + if ((FileData + index) ->NewFile !=3D NULL) { + free ((FileData + index)->NewFile); + (FileData + index)->NewFile =3D NULL; + } + if ((FileData + index)->OldFile !=3D NULL) { + free ((FileData + index)->OldFile); + (FileData + index)->OldFile =3D NULL; + } + } + for (index =3D 0; index < count; index ++) { + if ((FileData + index)->FdData !=3D NULL) { + LibFmmtFreeFd ((FileData + index)->FdData); + } + } + free (FileData); + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while delete some named ffs fil= e from the FD image file.", ""); + LibRmDir (TemDir); + return 1; + } + } else { + // + // Delete FV + // + Status =3D 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") =3D=3D 0) || (strcmp(Argv[0], "-A") = =3D=3D 0)) { + // + // Add some named FFS file into FD binary image. + // + if ((Argc - 3 ) % 2 !=3D 0) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the par= ameter is correct.", ""); + Usage (); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist =3D fopen (Argv[1], "rb"); + if (CheckFileExist =3D=3D NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please= make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + // + // Check whether the new added file exist or not. + // + for (index =3D 1; index < (Argc - 1) / 2; index ++) { + CheckFileExist =3D fopen(Argv[2 * index + 1], "rb"); + if (CheckFileExist =3D=3D NULL) { + Error("FMMT", 0, 0001, "Could not open the new FFS file, Pleas= e make sure the new FFS file exist.", Argv[2 * index + 1]); + return 1; + } + fclose(CheckFileExist); + } + + FileData =3D malloc(sizeof (Data) * (Argc - 3)/2); + if (FileData =3D=3D NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + return 1; + } + for(index =3D 0; index < (Argc - 3)/2; index ++) { + p =3D malloc(sizeof (FILENode)); + if (p =3D=3D NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", N= ULL); + free (FileData); + return 1; + } + p -> FileName =3D Argv[3 + index * 2]; + p -> SubLevel =3D 0; + exist =3D -1; + for (j =3D 0; j < count; j ++) { + if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) =3D= =3D 0)) { + exist =3D j; + break; + } + } + if (exist >=3D 0) { + p -> Next =3D (FileData + j) -> NewFile; + (FileData + j) -> NewFile =3D p; + } else { + (FileData + count) -> OldFile =3D NULL; + (FileData + count) -> FdData =3D NULL; + (FileData + count) -> FvLevel =3D 0; + (FileData + count) -> FvInFd =3D NULL; + (FileData + count) -> FvId =3D Argv[2 + index * 2]; + (FileData + count) -> NewFile =3D p; + p -> Next =3D NULL; + count ++; + } + } + + if (count <=3D 0) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering = information failed!"); + } + + for (index =3D 0; index < count; index ++) { + for (j =3D index + 1; j < count; j ++) { + if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) { + CHAR8 *tmp =3D (FileData + index)->FvId; + FILENode *temp =3D (FileData + index)->NewFile; + (FileData + index)->FvId =3D (FileData + j)->FvId; + (FileData + index)-> NewFile =3D (FileData + j)->NewFile; + (FileData + j)-> NewFile =3D temp; + (FileData + j)-> FvId =3D tmp; + } + } + } + + Status =3D FmmtImageAdd(Argv[1], FileData, count, Argv[Argc-1]); + for (index =3D 0; index < count; index ++) { + if ((FileData + index)->NewFile !=3D NULL) { + free ((FileData + index)->NewFile); + (FileData + index)->NewFile =3D NULL; + } + if ((FileData + index)->OldFile !=3D NULL) { + free ((FileData + index)->OldFile); + (FileData + index)->OldFile =3D NULL; + } + } + for (index =3D 0; index < count; index ++) { + if ((FileData + index)->FdData !=3D NULL) { + LibFmmtFreeFd ((FileData + index)->FdData); + } + } + free (FileData); + + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while add some named ffs file into th= e FD image file.", ""); + LibRmDir (TemDir); + return 1; + } + + } else if ((strcmp(Argv[0], "-r") =3D=3D 0) || (strcmp(Argv[0], "-R") = =3D=3D 0)) { + // + // Replace some named FFS file in the FD binary. + // + if ((Argc - 3) % 3 !=3D 0) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the par= ameter is correct.", ""); + Usage(); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist =3D fopen (Argv[1], "rb"); + if (CheckFileExist =3D=3D NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please= make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + // + // Check whether the new FFS file exist or not. + // + for (index =3D 1; index < Argc/3; index ++) { + CheckFileExist =3D fopen(Argv[3 * index + 1], "rb"); + if (CheckFileExist =3D=3D NULL) { + Error ("FMMT", 0, 0001, "Could not open the new FFS file, Plea= se make sure the new FFS file exist.", Argv[3 * index + 1]); + return 1; + } + fclose(CheckFileExist); + } + + FileData =3D malloc(sizeof (Data) * (Argc - 3)/3); + if (FileData =3D=3D NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + return 1; + } + for(index =3D 0; index < (Argc - 3)/3; index ++) { + p =3D malloc(sizeof (FILENode)); //p for old file + if (p =3D=3D NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", N= ULL); + free (FileData); + return 1; + } + q =3D malloc(sizeof (FILENode)); //q for new file + if (q =3D=3D NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", N= ULL); + free (FileData); + free (p); + return 1; + } + p -> FileName =3D Argv[3 + index * 3]; + q -> FileName =3D Argv[4 + index * 3]; + p -> SubLevel =3D 0; + q -> SubLevel =3D 0; + exist =3D -1; + for (j =3D 0; j < count; j ++) { + if ((strcmp(Argv[2 + index * 3], (FileData + j) -> FvId) =3D= =3D 0)) { + exist =3D j; + break; + } + } + if (exist >=3D 0) { + p -> Next =3D (FileData + j) -> OldFile; + (FileData + j) -> OldFile =3D p; + q -> Next =3D (FileData + j) -> NewFile; + (FileData + j) -> NewFile =3D q; + } else { + (FileData + count) -> FdData =3D NULL; + (FileData + count) -> FvLevel =3D 0; + (FileData + count) -> FvInFd =3D NULL; + (FileData + count) -> FvId =3D Argv[2 + index * 3];; + (FileData + count) -> OldFile =3D p; + (FileData + count) -> NewFile =3D q; + p -> Next =3D NULL; + q -> Next =3D NULL; + count ++; + } + } + + if (count <=3D 0) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering = information failed!"); + } + for (index =3D 0; index < count; index ++) { + for (j =3D index + 1; j < count; j ++) { + if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < = 0)) { + CHAR8 *tmp =3D (FileData + index)->FvId; + FILENode *Old =3D (FileData + index)->OldFile; + FILENode *New =3D (FileData + index)->NewFile; + (FileData + index)->FvId =3D (FileData + j)->FvId; + (FileData + index)->OldFile =3D (FileData + j)->OldFile; + (FileData + index)->NewFile =3D (FileData + j)->NewFile; + (FileData + j)->OldFile =3D Old; + (FileData + j)->NewFile =3D New; + (FileData + j)->FvId =3D tmp; + } + } + } + + Status =3D FmmtImageReplace(Argv[1], FileData, count, Argv[Argc-1]); + for (index =3D 0; index < count; index ++) { + if ((FileData + index)->NewFile !=3D NULL) { + free ((FileData + index)->NewFile); + (FileData + index)->NewFile =3D NULL; + } + if ((FileData + index)->OldFile !=3D NULL) { + free ((FileData + index)->OldFile); + (FileData + index)->OldFile =3D NULL; + } + } + for (index =3D 0; index < count; index ++) { + if ((FileData + index)->FdData !=3D NULL) { + LibFmmtFreeFd ((FileData + index)->FdData); + } + } + free (FileData); + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while replace the named ffs file in t= he FD image file with the new ffs file.", ""); + LibRmDir (TemDir); + return 1; + } + + } else if ((strcmp(Argv[0], "-h") =3D=3D 0) || (strcmp(Argv[0], "--help"= ) =3D=3D 0) || + (strcmp(Argv[0], "-?") =3D=3D 0) || (strcmp(Argv[0], "/?") = =3D=3D 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/Platfor= m/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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _BIN_FILE_MANAGER_ +#define _BIN_FILE_MANAGER_ + +#include +#include +#include +#ifdef __GNUC__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include + +#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 infor= mation + // + 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/FMM= T/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.
+ 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) =3D=3D Bit) : ((TestAttributes & Bit) =3D=3D Bit) \ + ) \ + ) + +CHAR8 mFirmwareFileSystem2Guid[16] =3D {0x78, 0xE5, 0x8C, 0x8C, 0x3D,= 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3}; + +CHAR8 mFirmwareFileSystem3Guid[16] =3D {0x7A, 0xC0, 0x73, 0x54, 0xCB,= 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A }; + +EFI_GUID mEfiCrc32GuidedSectionExtractionProtocolGuid =3D EFI_CRC32_GUID= ED_SECTION_EXTRACTION_PROTOCOL_GUID; +extern CHAR8* mGuidToolDefinition; + +static CHAR8 *mSectionTypeName[] =3D { + 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[] =3D { + 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[] =3D { + "NONE", // 0x00 + "PROCESSING_REQUIRED", // 0x01 + "AUTH_STATUS_VALID" // 0x02 +}; + +static EFI_GUID mFvUiGuid =3D { + 0xA67DF1FA, 0x8DE8, 0x4E98, { + 0xAF, 0x09, 0x4B, 0xDF, 0x2E, 0xFF, 0xBC, 0x7C + } +}; + + +/** + Generate the unique template filename. +**/ +CHAR8 * +GenTempFile ( + VOID + ) +{ + CHAR8 *TemString; + TemString =3D NULL; +#ifndef __GNUC__ + TemString =3D CloneString (tmpnam (NULL)); +#else + CHAR8 tmp[] =3D "/tmp/fileXXXXXX"; + UINTN Fdtmp; + Fdtmp =3D mkstemp(tmp); + TemString =3D CloneString(tmp); + close(Fdtmp); +#endif + return TemString; +} + +static +EFI_STATUS +LibExtractFvUiName(CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader, CHAR= 8 **FvUiName) +{ + UINT8 *ExtEnd; + UINT32 ExtDataSize; + EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntry; + EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *GuidEntry; + + + ExtEnd =3D (UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize; + ExtEntry =3D (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(FvExtHeader + 1); + while ((UINT8 *)ExtEntry < ExtEnd) { + // + // GUID type EXT + // + if (ExtEntry->ExtEntryType =3D=3D 0x0002) { + GuidEntry =3D (EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *)ExtEntry; + if (memcmp(&GuidEntry->FormatType, &mFvUiGuid, sizeof(EFI_GUID)) =3D= =3D 0) { + ExtDataSize =3D ExtEntry->ExtEntrySize - (sizeof(EFI_GUID)+sizeof(= *ExtEntry)); + *FvUiName =3D malloc(ExtDataSize + 1); + if (*FvUiName !=3D NULL) { + memcpy(*FvUiName, (UINT8 *)GuidEntry + sizeof(EFI_GUID)+sizeof(*= ExtEntry), ExtDataSize); + (*FvUiName)[ExtDataSize] =3D '\0'; + return EFI_SUCCESS; + } + } + } + + ExtEntry =3D (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtEntry + Ext= Entry->ExtEntrySize); + } + return EFI_NOT_FOUND; +} + +FV_INFORMATION * +LibInitializeFvStruct ( + FV_INFORMATION *Fv +) +{ + UINT32 Index; + + if (Fv =3D=3D NULL) { + return NULL; + } + + for (Index =3D 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 =3D 0; + Fv->FfsAttuibutes[Index].IsLeaf =3D TRUE; + Fv->FfsAttuibutes[Index].Level =3D 0xFF; + Fv->FfsAttuibutes[Index].TotalSectionNum =3D 0; + Fv->FfsAttuibutes[Index].Depex =3D NULL; + Fv->FfsAttuibutes[Index].DepexLen =3D 0; + Fv->FfsAttuibutes[Index].IsHandle =3D FALSE; + Fv->FfsAttuibutes[Index].IsFvStart =3D FALSE; + Fv->FfsAttuibutes[Index].IsFvEnd =3D FALSE; + } + + Fv->EncapData =3D NULL; + Fv->FvNext =3D NULL; + Fv->ChildFvFFS =3D NULL; + Fv->FvLevel =3D 0; + Fv->MulFvLevel =3D 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] =3D ""; + CHAR8 Signature[5] =3D "_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 =3D NULL; + NewFoundFv =3D NULL; + FdBuffer =3D NULL; + FdBufferOri =3D NULL; + FirstMatch =3D TRUE; + Index =3D 0; + FdSize =3D 0; + FvCount =3D 0; + LocalFdData =3D NULL; + + if (InputFile =3D=3D 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 =3D ftell(InputFile); + + fseek(InputFile,0,SEEK_SET); + // + // Create an FD structure to store useful information. + // + LocalFdData =3D (FIRMWARE_DEVICE *) malloc (sizeof (FIRMWARE_DEVICE)= ); + if (LocalFdData =3D=3D NULL) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Alloca= te memory error"); + return EFI_OUT_OF_RESOURCES; + } + LocalFdData->Fv =3D (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION)); + if (LocalFdData->Fv =3D=3D NULL) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Alloca= te memory error"); + free (LocalFdData); + return EFI_OUT_OF_RESOURCES; + } + + LibInitializeFvStruct (LocalFdData->Fv); + + // + // Readout the FD file data to buffer. + // + FdBuffer =3D malloc (FdSize); + + if (FdBuffer =3D=3D NULL) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Alloca= te memory error"); + free (LocalFdData->Fv); + free (LocalFdData); + return EFI_OUT_OF_RESOURCES; + } + + if (fread (FdBuffer, 1, FdSize, InputFile) !=3D FdSize) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Read F= D file error!"); + free (LocalFdData->Fv); + free (LocalFdData); + free (FdBuffer); + return EFI_ABORTED; + } + + FdBufferOri =3D FdBuffer; + FdBufferEnd =3D FdBuffer + FdSize; + + while (FdBuffer <=3D FdBufferEnd - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) { + FvHeader =3D (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) =3D=3D 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 =3D 0; Index < 16; Index ++) { + if (Ffs2Guid[Index] !=3D mFirmwareFileSystem2Guid[Index]) { + break; + } + } + if (Index !=3D 16) { + for (Index =3D 0; Index < 16; Index ++) { + if (Ffs2Guid[Index] !=3D mFirmwareFileSystem3Guid[Index]) { + break; + } + } + } + + // + // Here we found an FV. + // + if ((Index =3D=3D 16) && ((FdBuffer + FvHeader->FvLength) <=3D FdBuf= ferEnd)) { + if (FirstMatch) { + LocalFdData->Fv->ImageAddress =3D (UINTN)((UINT8 *)FdBuffer - (U= INT8 *)FdBufferOri); + CurrentFv =3D LocalFdData->Fv; + CurrentFv->FvNext =3D NULL; + // + // Store the FV name by found sequence + // + sprintf(CurrentFv->FvName, "FV%d", FvCount); + + FirstMatch =3D FALSE; + } else { + NewFoundFv =3D (FV_INFORMATION *) malloc (sizeof (FV_INFORMATI= ON)); + if (NewFoundFv =3D=3D 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 =3D (UINTN)((UINT8 *)FdBuffer - (UINT= 8 *)FdBufferOri); + + // + // Store the FV name by found sequence + // + sprintf(NewFoundFv->FvName, "FV%d", FvCount); + + // + // Value it to NULL for found FV usage. + // + NewFoundFv->FvNext =3D NULL; + CurrentFv->FvNext =3D NewFoundFv; + + // + // Make the CurrentFv point to next FV. + // + CurrentFv =3D CurrentFv->FvNext; + } + + FvCount ++; + FdBuffer =3D FdBuffer + FvHeader->FvLength; + } else { + FdBuffer ++; + } + + } else { + FdBuffer ++; + } + } + + LocalFdData->Size =3D FdSize; + + *FdData =3D LocalFdData; + + free (FdBufferOri); + + return EFI_SUCCESS; +} + +UINTN +GetFreeOffset ( + IN VOID *InputFv +) +{ + UINTN FreeOffset; + UINTN Offset; + EFI_STATUS Status; + EFI_FFS_FILE_HEADER2 *CurrentFile; + + Offset =3D 0; + CurrentFile =3D NULL; + FreeOffset =3D 0; + do { + FreeOffset =3D (UINTN)ALIGN_POINTER(Offset, 8); + Status =3D FvBufFindNextFile(InputFv, &Offset, (VOID **)&CurrentFile); + if (Status =3D=3D EFI_NOT_FOUND) { + CurrentFile =3D NULL; + break; + } + else if (EFI_ERROR(Status)) { + return Status; + } + } while (CurrentFile !=3D 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 =3D 0; + RetStr =3D NULL; + + RetStr =3D (CHAR8 *) malloc (Count +1); + + if (RetStr =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return NULL; + } + + memset (RetStr , '\0', Count + 1); + + for (Index=3D0; Index <=3D Count -1; Index ++) { + RetStr[Index] =3D ' '; + } + + 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 =3D NULL; + FvUiName =3D NULL; + + // + // Check input parameters + // + if (InputFv =3D=3D NULL) { + Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid param= eter to function"); + return EFI_INVALID_PARAMETER; + } + + // + // Read the header + // + VolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) InputFv; + + + BlankSpace =3D LibConstructBlankChar((FvLevel)*2); + + if (BlankSpace =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_OUT_OF_RESOURCES; + } + + + if (ViewFlag) { + if ((FvLevel -1) =3D=3D 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) Volu= meHeader->Attributes); + printf ("%sTotal Volume Size: 0x%08X\n", BlankSpace, (unsigned) Vo= lumeHeader->FvLength); + printf ("%sFree Volume Size: 0x%08X\n", BlankSpace, (unsigned) (V= olumeHeader->FvLength - GetFreeOffset(InputFv))); + } + + if (ViewFlag && VolumeHeader->ExtHeaderOffset !=3D 0) { + FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)VolumeHead= er + 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 !=3D NULL && FvLevel =3D=3D 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 =3D 0; + Size =3D 0; + + if (InputFile =3D=3D NULL || FvSize =3D=3D NULL) { + Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid param= eter to function"); + return EFI_INVALID_PARAMETER; + } + + fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_B= LOCK_MAP_ENTRY), SEEK_CUR); + do { + fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile); + BytesRead +=3D sizeof (EFI_FV_BLOCK_MAP_ENTRY); + + if (BlockMap.NumBlocks !=3D 0) { + Size +=3D BlockMap.NumBlocks * BlockMap.Length; + } + } while (!(BlockMap.NumBlocks =3D=3D 0 && BlockMap.Length =3D=3D 0)); + + + *FvSize =3D 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 =3D 0; + hdr =3D (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + blk =3D hdr->BlockMap; + + while (blk->Length !=3D 0 || blk->NumBlocks !=3D 0) { + *Size =3D *Size + (blk->Length * blk->NumBlocks); + if (*Size >=3D 0x40000000) { + // + // If size is greater than 1GB, then assume it is corrupted + // + return EFI_VOLUME_CORRUPTED; + } + blk++; + } + + if (*Size =3D=3D 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 =3D 0; + FfsFileName =3D NULL; + FfsFile =3D NULL; + TempDir =3D NULL; + + TempDir =3D getcwd (NULL, _MAX_PATH); + if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MA= X_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 =3D (CHAR8 *) malloc (_MAX_PATH); + if (FfsFileName =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + memset (FfsFileName, '\0', _MAX_PATH); + FfsFileSize =3D 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->Nam= e, sizeof(EFI_GUID)); + // + // Update current FFS files file state. + // + if (ErasePolarity) { + CurrentFile->State =3D (UINT8)~(CurrentFile->State); + } + + FfsFile =3D fopen (FfsFileName, "wb+"); + if (FfsFile =3D=3D 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) !=3D FfsFileSize) { + Error ("FMMT", 0, 0004, "error writing FFS file", "cannot Create a ne= w ffs file."); + fclose(FfsFile); + free(FfsFileName); + return EFI_ABORTED; + } + + fclose(FfsFile); + free(FfsFileName); + FfsFileName =3D NULL; + + CurrentFv->FfsNumbers =3D *FfsCount; + + *FfsCount +=3D 1; + + if (ErasePolarity) { + CurrentFile->State =3D (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 stri= ng. + + 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 !=3D '\0') { + *(Destination++) =3D (CHAR8) *(Source++); + } + // + // End the ascii with a NULL. + // + *Destination =3D '\0'; +} + + +/** + + Parses EFI Sections, if the view flag turn on, then will collect FFS sec= tion 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 =3D 0; + GuidAttr =3D 0; + ParsedLength =3D 0; + ToolOutputLength =3D 0; + UINameSize =3D 0; + NumberOfSections =3D 0; + UncompressedLength =3D 0; + CompressedLength =3D 0; + CompressionType =3D 0; + DstSize =3D 0; + ScratchSize =3D 0; + Ptr =3D NULL; + ExtractionTool =3D NULL; + ToolInputFile =3D NULL; + ToolOutputFile =3D NULL; + SystemCommand =3D NULL; + SystemCommandFormatString =3D NULL; + ToolOutputBuffer =3D NULL; + UIName =3D NULL; + LocalEncapData =3D NULL; + LocalEncapDataTemp =3D NULL; + BlankChar =3D NULL; + UncompressedBuffer =3D NULL; + CompressedBuffer =3D NULL; + ScratchBuffer =3D NULL; + TempDir =3D NULL; + ToolInputFileFullName =3D NULL; + ToolOutputFileFullName =3D NULL; + ToolInputFileName =3D NULL; + ToolOutputFileFullName =3D NULL; + HasDepexSection =3D FALSE; + EncapDataNeedUpdata =3D TRUE; + LargeHeaderOffset =3D 0; + + + while (ParsedLength < BufferLength) { + Ptr =3D SectionBuffer + ParsedLength; + + SectionLength =3D GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size= ); + Type =3D ((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 se= ction + // header worth of 0xFF bytes. + // + if (SectionLength =3D=3D 0xffffff && Type =3D=3D 0xff) { + ParsedLength +=3D 4; + continue; + } + // + //If Size is 0xFFFFFF then ExtendedSize contains the size of the section. + // + if (SectionLength =3D=3D 0xffffff) { + SectionLength =3D ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSi= ze; + LargeHeaderOffset =3D sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EF= I_COMMON_SECTION_HEADER); + } + + switch (Type) { + + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: + + EncapDataNeedUpdata =3D TRUE; + + Level ++; + NumberOfSections ++; + + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf =3D FALSE; + CurrentFv->FfsAttuibutes[*FfsCount].IsFvStart =3D TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData =3D *CurrentFvEncapData; + if (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + while (LocalEncapData->RightNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->RightNode; + } + } + + if (EncapDataNeedUpdata) { + // + // Put in this is an FFS with FV section + // + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (E= NCAP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_FV_SECTION; + + // + // We don't need additional data for encapsulate this FFS but type. + // + LocalEncapData->Data =3D NULL; + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->NextNode =3D NULL; + LocalEncapData->RightNode =3D NULL; + LocalEncapData->Depex =3D NULL; + LocalEncapData->DepexLen =3D 0; + LocalEncapData->UiNameSize =3D 0; + LocalEncapData->FvId =3D *FvCount; + } + + // + //save parent level FFS file's GUID name + // + LocalEncapDataTemp =3D CurrentFv->EncapData; + while (LocalEncapDataTemp->NextNode !=3D NULL) { + if (LocalEncapDataTemp->Level =3D=3D FfsLevel) { + while (LocalEncapDataTemp->RightNode !=3D NULL) { + LocalEncapDataTemp =3D LocalEncapDataTemp->RightNode; + } + if (LocalEncapDataTemp !=3D NULL && LocalEncapDataTemp->FvExt= Header =3D=3D NULL) { + LocalEncapDataTemp->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_= EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)); + if (LocalEncapDataTemp->FvExtHeader =3D=3D NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't be alloc= ated", NULL); + return EFI_ABORTED; + } + + if (*FfsCount >=3D 1) { + if ((memcmp(&CurrentFv->FfsAttuibutes[*FfsCount - 1].G= uidName, &(LocalEncapDataTemp->FvExtHeader->FvName), sizeof(EFI_GUID)) =3D= =3D 0)) { + memcpy(LocalEncapDataTemp->UiName, CurrentFv->FfsA= ttuibutes[*FfsCount - 1].UiName, _MAX_PATH); + LocalEncapDataTemp->UiNameSize =3D CurrentFv->FfsA= ttuibutes[*FfsCount - 1].UiNameSize; + LocalEncapDataTemp->DepexLen =3D CurrentFv->FfsAtt= uibutes[*FfsCount - 1].DepexLen; + LocalEncapDataTemp->Depex =3D malloc (LocalEncapDa= taTemp->DepexLen); + if (LocalEncapDataTemp->Depex =3D=3D NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't b= e allocated", NULL); + return EFI_ABORTED; + } + memcpy(LocalEncapDataTemp->Depex, CurrentFv->FfsAt= tuibutes[*FfsCount - 1].Depex, LocalEncapDataTemp->DepexLen); + } + } + } + break; + } + LocalEncapDataTemp =3D LocalEncapDataTemp->NextNode; + } + + Status =3D 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 >=3D 1) { + CurrentFv->FfsAttuibutes[*FfsCount -1].IsFvEnd =3D TRUE; + } + break; + + case EFI_SECTION_COMPRESSION: + Level ++; + NumberOfSections ++; + + EncapDataNeedUpdata =3D TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData =3D *CurrentFvEncapData; + if (LocalEncapData->NextNode !=3D NULL) { + EncapDataNeedUpdata =3D FALSE; + while (LocalEncapData->RightNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->RightNode; + } + } + + if (EncapDataNeedUpdata) { + // + // Put in this is an FFS with FV section + // + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (E= NCAP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_COMPRESS_SECTION; + + // + // Store the compress type + // + LocalEncapData->Data =3D malloc (sizeof (UINT8)); + + if (LocalEncapData->Data =3D=3D NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + + *(UINT8 *)LocalEncapData->Data =3D ((EFI_COMPRESSION_SECTION *= ) (Ptr + LargeHeaderOffset))->CompressionType; + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->NextNode =3D NULL; + LocalEncapData->RightNode =3D NULL; + } else { + LocalEncapData->RightNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (= ENCAP_INFO_DATA)); + if (LocalEncapData->RightNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + LocalEncapData =3D LocalEncapData->RightNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_COMPRESS_SECTION; + + // + // Store the compress type + // + LocalEncapData->Data =3D malloc (sizeof (UINT8)); + + if (LocalEncapData->Data =3D=3D NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + + *(UINT8 *)LocalEncapData->Data =3D ((EFI_COMPRESSION_SECTION *= ) (Ptr + LargeHeaderOffset))->CompressionType; + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->NextNode =3D NULL; + LocalEncapData->RightNode =3D NULL; + + } + + // + // Process compressed section + // + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf =3D FALSE; + + UncompressedBuffer =3D NULL; + CompressedLength =3D SectionLength - sizeof (EFI_COMPRESSION_SECT= ION) - LargeHeaderOffset; + UncompressedLength =3D ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHea= derOffset))->UncompressedLength; + CompressionType =3D ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHea= derOffset))->CompressionType; + + if (CompressionType =3D=3D EFI_NOT_COMPRESSED) { + //printf (" Compression Type: EFI_NOT_COMPRESSED\n"); + if (CompressedLength !=3D 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 =3D Ptr + sizeof (EFI_COMPRESSION_SECTION) + La= rgeHeaderOffset; + } else if (CompressionType =3D=3D EFI_STANDARD_COMPRESSION) { + GetInfoFunction =3D EfiGetInfo; + DecompressFunction =3D EfiDecompress; + + CompressedBuffer =3D Ptr + sizeof (EFI_COMPRESSION_SECTION) + Lar= geHeaderOffset; + + Status =3D GetInfoFunction (CompressedBuffer, Compresse= dLength, &DstSize, &ScratchSize); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "error getting compression info from com= pression section", NULL); + return EFI_SECTION_ERROR; + } + + if (DstSize !=3D UncompressedLength) { + Error ("FMMT", 0, 0003, "compression error in the compression se= ction", NULL); + return EFI_SECTION_ERROR; + } + + ScratchBuffer =3D malloc (ScratchSize); + if (ScratchBuffer =3D=3D NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + UncompressedBuffer =3D malloc (UncompressedLength); + if (UncompressedBuffer =3D=3D NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + free (ScratchBuffer); + return EFI_OUT_OF_RESOURCES; + } + // + // Decompress the section. + // + Status =3D 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 =3D LibParseSection ( UncompressedBuffer, + UncompressedLength, + CurrentFv, + FvName, + CurrentFile, + Level, + &LocalEncapData, + FfsLevel, + FfsCount, + FvCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated); + + if (CompressionType =3D=3D 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 =3D TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData =3D *CurrentFvEncapData; + if (LocalEncapData->NextNode !=3D NULL) { + EncapDataNeedUpdata =3D FALSE; + while (LocalEncapData->RightNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->RightNode; + } + } + GuidAttr =3D ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))= ->Attributes; + DataOffset =3D ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset= ))->DataOffset; + + if ((ViewFlag) && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRE= D) =3D=3D 0)) { + ToolOutputBuffer =3D Ptr + DataOffset; + ToolOutputLength =3D SectionLength - DataOffset; + Status =3D 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", N= ULL); + return EFI_SECTION_ERROR; + } + break; + } + + if (EncapDataNeedUpdata) { + + // + // Put in this is an FFS with FV section + // + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (E= NCAP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_GUIDED_SECTION; + LocalEncapData->Depex =3D NULL; + LocalEncapData->DepexLen =3D 0; + LocalEncapData->UiNameSize =3D 0; + // + // We don't need additional data for encapsulate this FFS but type. + // include DataOffset + Attributes + // + + LocalEncapData->Data =3D (EFI_GUID *) malloc (sizeof (EFI_GUID= ) + 4); + + if (LocalEncapData->Data =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + 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 =3D NULL; + LocalEncapData->NextNode =3D NULL; + LocalEncapData->RightNode =3D NULL; + } else { + LocalEncapData->RightNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (= ENCAP_INFO_DATA)); + if (LocalEncapData->RightNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + LocalEncapData =3D LocalEncapData->RightNode; + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_GUIDED_SECTION; + LocalEncapData->Depex =3D NULL; + LocalEncapData->DepexLen =3D 0; + LocalEncapData->UiNameSize =3D 0; + // + // We don't need additional data for encapsulate this FFS but type. + // include DataOffset + Attributes + // + + LocalEncapData->Data =3D (EFI_GUID *) malloc (sizeof (EFI_GUID= ) + 4); + + if (LocalEncapData->Data =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + 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 =3D NULL; + LocalEncapData->NextNode =3D NULL; + LocalEncapData->RightNode =3D NULL; + } + + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf =3D FALSE; + + ExtractionTool =3D + LookupGuidedSectionToolPath ( + mParsedGuidedSectionTools, + &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->Secti= onDefinitionGuid + ); + + if (ExtractionTool !=3D NULL && ((GuidAttr & EFI_GUIDED_SECTION_PROC= ESSING_REQUIRED) !=3D 0)) { + + TempDir =3D 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 =3D GenTempFile (); + if (ToolInputFile =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + free (ExtractionTool); + return EFI_OUT_OF_RESOURCES; + } + ToolOutputFile =3D GenTempFile (); + if (ToolOutputFile =3D=3D NULL) { + free (ToolInputFile); + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + free (ExtractionTool); + return EFI_OUT_OF_RESOURCES; + } + ToolInputFileName =3D strrchr(ToolInputFile, OS_SEP); + if (ToolInputFileName =3D=3D NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ExtractionTool); + return EFI_ABORTED; + } + ToolOutputFileName =3D strrchr(ToolOutputFile, OS_SEP); + if (ToolOutputFileName =3D=3D NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ExtractionTool); + return EFI_ABORTED; + } + + ToolInputFileFullName =3D malloc (strlen("%s%s") + strlen(TempDi= r) + strlen(ToolInputFileName) + 1); + if (ToolInputFileFullName =3D=3D NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ExtractionTool); + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + ToolOutputFileFullName =3D malloc (strlen("%s%s") + strlen(TempDi= r) + strlen(ToolOutputFileName) + 1); + + if (ToolOutputFileFullName =3D=3D NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ToolInputFileFullName); + free (ExtractionTool); + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_OUT_OF_RESOURCES; + } + + sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName= ); + sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileNa= me); + + // + // Construction 'system' command string + // + SystemCommandFormatString =3D "%s -d -o \"%s\" \"%s\""; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (ExtractionTool) + + strlen (ToolInputFileFullName) + + strlen (ToolOutputFileFullName) + + 1 + ); + if (SystemCommand =3D=3D 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 =3D NULL; + + Status =3D PutFileImage ( + ToolInputFileFullName, + (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOff= set))->DataOffset, + SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOf= fset))->DataOffset + ); + + if (HasDepexSection) { + HasDepexSection =3D 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) !=3D 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 =3D NULL; + ToolInputFileFullName =3D NULL; + + + Status =3D GetFileImage ( + ToolOutputFileFullName, + (CHAR8 **)&ToolOutputBuffer, + &ToolOutputLength + ); + remove (ToolOutputFileFullName); + free (ToolOutputFile); + free (ToolOutputFileFullName); + ToolOutputFile =3D NULL; + ToolOutputFileFullName =3D NULL; + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "unable to read decoded GUIDED section",= NULL); + return EFI_SECTION_ERROR; + } + + Status =3D 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) =3D= =3D 0){ + Status =3D LibParseSection ( + Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))= ->DataOffset, + SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHead= erOffset))->DataOffset, + CurrentFv, + FvName, + CurrentFile, + Level, + &LocalEncapData, + FfsLevel, + FfsCount, + FvCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated + ); + if (ExtractionTool !=3D NULL) { + free (ExtractionTool); + ExtractionTool =3D 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 !=3D NULL) { + free (ExtractionTool); + ExtractionTool =3D NULL; + } + Error ("FMMT", 0, 0003, "Error parsing section", \ + "EFI_SECTION_GUID_DEFINED cannot be parsed a= t this time. Tool to decode this section should have been defined in %s fil= e.", 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 =3D Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + *IsFfsGenerated =3D TRUE; + } + } + + break; + case EFI_SECTION_PE32: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + *IsFfsGenerated =3D TRUE; + } + } + + break; + case EFI_SECTION_PIC: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + *IsFfsGenerated =3D TRUE; + } + } + + break; + case EFI_SECTION_TE: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + *IsFfsGenerated =3D TRUE; + } + } + break; + + case EFI_SECTION_COMPATIBILITY16: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + *IsFfsGenerated =3D TRUE; + } + } + break; + + case EFI_SECTION_FREEFORM_SUBTYPE_GUID: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + *IsFfsGenerated =3D TRUE; + } + } + break; + + case EFI_SECTION_VERSION: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + break; + case EFI_SECTION_PEI_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + HasDepexSection =3D TRUE; + CurrentFv->FfsAttuibutes[*FfsCount].Depex =3D malloc (SectionLength); + memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength= ); + CurrentFv->FfsAttuibutes[*FfsCount].DepexLen =3D SectionLength; + break; + case EFI_SECTION_DXE_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + HasDepexSection =3D TRUE; + CurrentFv->FfsAttuibutes[*FfsCount].Depex =3D malloc (SectionLength); + memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength= ); + CurrentFv->FfsAttuibutes[*FfsCount].DepexLen =3D SectionLength; + break; + case EFI_SECTION_SMM_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + HasDepexSection =3D TRUE; + CurrentFv->FfsAttuibutes[*FfsCount].Depex =3D malloc (SectionLength); + memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength= ); + CurrentFv->FfsAttuibutes[*FfsCount].DepexLen =3D SectionLength; + break; + + case EFI_SECTION_USER_INTERFACE: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + + UiSectionLength =3D GetLength (((EFI_USER_INTERFACE_SECTION *) Ptr)-= >CommonHeader.Size); + if (UiSectionLength =3D=3D 0xffffff) { + UiSectionLength =3D ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonH= eader.ExtendedSize; + UINameSize =3D UiSectionLength - sizeof(EFI_COMMON_SECTION_HEAD= ER2); + } else { + UINameSize =3D UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER); + } + + UIName =3D (CHAR16 *) malloc (UINameSize + 2); + if (UIName !=3D NULL) { + memset (UIName, '\0', UINameSize + 2); + if (UiSectionLength >=3D 0xffffff) { + memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameSt= ring, UINameSize); + } else { + memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameStr= ing, UINameSize); + } + } else { + Error ("FMMT", 0, 0001, "Memory allocate error!", NULL); + return EFI_OUT_OF_RESOURCES; + } + + BlankChar =3D LibConstructBlankChar( CurrentFv->FvLevel * 2); + if (BlankChar =3D=3D NULL) { + free(UIName); + return EFI_OUT_OF_RESOURCES; + } + + if (ViewFlag) { + UIFileName =3D malloc (UINameSize + 2); + if (UIFileName =3D=3D 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, UIN= ameSize); + CurrentFv->FfsAttuibutes[*FfsCount -1].UiNameSize =3D UINameSize; + } else { + memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UIName= Size); + CurrentFv->FfsAttuibutes[*FfsCount].UiNameSize =3D UINameSize; + } + + HasDepexSection =3D FALSE; + free(UIName); + UINameSize =3D 0; + + break; + default: + break; + } + + ParsedLength +=3D SectionLength; + // + // We make then next section begin on a 4-byte boundary + // + ParsedLength =3D 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 s= hould be + passed back in without modifying it's contents to re= trieve + subsequent files. + @param[in] File- Output file pointer + File =3D=3D 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 =3D (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + fhdr =3D NULL; + + if (Fv =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*Key =3D=3D 0) { + if (hdr->ExtHeaderOffset !=3D 0) { + // + // Searching for files starts on an 8 byte aligned boundary after th= e end of the Extended Header if it exists. + // + FwVolExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)hdr += hdr->ExtHeaderOffset); + *Key =3D (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSize; + *Key =3D (UINTN)ALIGN_POINTER(*Key, 8); + } else { + *Key =3D hdr->HeaderLength; + } + } + + FvbAttributes =3D hdr->Attributes; + + for( + *Key =3D (UINTN)ALIGN_POINTER (*Key, 8); + (*Key + sizeof (*fhdr)) < fvSize; + *Key =3D (UINTN)ALIGN_POINTER (*Key, 8) + ) { + fhdr =3D (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key); + fsize =3D 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 =3D *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 =3D *Key + fsize; + continue; + } else if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DATA_VALID + ) + ) { + *File =3D (UINT8*)hdr + *Key; + *Key =3D *Key + fsize; + return EFI_SUCCESS; + } + + *Key =3D *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 =3D EFI_SUCCESS; + + LocalEncapData =3D NULL; + EncapDataNeedUpdateFlag =3D TRUE; + IsGeneratedFfs =3D FALSE; + + FfsFileHeaderSize =3D GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) Curre= ntFile); + FileLength =3D GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentF= ile); + + // + // 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) =3D=3D 0) { + return EFI_SUCCESS; + } + + // + // Print file information. + // + FileState =3D GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)Curren= tFile); + PrintGuidToBuffer (&(CurrentFile->Name), GuidBuffer, PRINTED_GUID_BUFFER= _SIZE, FALSE); + if (FileState =3D=3D EFI_FILE_DATA_VALID) { + // + // Calculate header checksum + // + Checksum =3D CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize); + Checksum =3D (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum= .File); + Checksum =3D (UINT8) (Checksum - CurrentFile->State); + if (Checksum !=3D 0) { + Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Gui= d %s has invalid header checksum", GuidBuffer); + return EFI_ABORTED; + } + + if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Calculate file checksum + // + Checksum =3D CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFile= HeaderSize), FileLength - FfsFileHeaderSize); + Checksum =3D Checksum + CurrentFile->IntegrityCheck.Checksum.File; + if (Checksum !=3D 0) { + Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with G= uid %s has invalid file checksum", GuidBuffer); + return EFI_ABORTED; + } + } else { + if (CurrentFile->IntegrityCheck.Checksum.File !=3D FFS_FIXED_CHECKSU= M) { + Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with G= uid %s has invalid header checksum -- not set to fixed value of 0xAA", Guid= Buffer); + 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 +=3D 1; + + if ((CurrentFile->Type !=3D EFI_FV_FILETYPE_ALL) && (CurrentFile->Type != =3D EFI_FV_FILETYPE_FFS_PAD)) { + + // + // Put in encapsulate data information. + // + LocalEncapData =3D *CurrentFvEncapData; + if (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + EncapDataNeedUpdateFlag =3D FALSE; + while (LocalEncapData->RightNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->RightNode; + } + } + + if (EncapDataNeedUpdateFlag) { + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (ENC= AP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_FFS; + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->Depex =3D NULL; + LocalEncapData->DepexLen =3D 0; + LocalEncapData->UiNameSize =3D 0; + // + // Store the header of FFS file. + // + LocalEncapData->Data =3D malloc (FfsFileHeaderSize); + if (LocalEncapData->Data =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize); + LocalEncapData->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *)ma= lloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)); + if (LocalEncapData->FvExtHeader =3D=3D NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + LocalEncapData->FvExtHeader->FvName.Data1 =3D CurrentFile->Name.Data= 1; + LocalEncapData->FvExtHeader->FvName.Data2 =3D CurrentFile->Name.Data= 2; + LocalEncapData->FvExtHeader->FvName.Data3 =3D CurrentFile->Name.Data= 3; + LocalEncapData->FvExtHeader->FvName.Data4[0] =3D CurrentFile->Name.D= ata4[0]; + LocalEncapData->FvExtHeader->FvName.Data4[1] =3D CurrentFile->Name.D= ata4[1]; + LocalEncapData->FvExtHeader->FvName.Data4[2] =3D CurrentFile->Name.D= ata4[2]; + LocalEncapData->FvExtHeader->FvName.Data4[3] =3D CurrentFile->Name.D= ata4[3]; + LocalEncapData->FvExtHeader->FvName.Data4[4] =3D CurrentFile->Name.D= ata4[4]; + LocalEncapData->FvExtHeader->FvName.Data4[5] =3D CurrentFile->Name.D= ata4[5]; + LocalEncapData->FvExtHeader->FvName.Data4[6] =3D CurrentFile->Name.D= ata4[6]; + LocalEncapData->FvExtHeader->FvName.Data4[7] =3D CurrentFile->Name.D= ata4[7]; + LocalEncapData->NextNode =3D NULL; + LocalEncapData->RightNode =3D NULL; + }else{ + // + // Construct the new ENCAP_DATA + // + LocalEncapData->RightNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (EN= CAP_INFO_DATA)); + + if (LocalEncapData->RightNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->RightNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_FFS; + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->Depex =3D NULL; + LocalEncapData->DepexLen =3D 0; + LocalEncapData->UiNameSize =3D 0; + // + // Store the header of FFS file. + // + LocalEncapData->Data =3D malloc (FfsFileHeaderSize); + if (LocalEncapData->Data =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize); + LocalEncapData->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *)ma= lloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)); + if (LocalEncapData->FvExtHeader =3D=3D NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + LocalEncapData->FvExtHeader->FvName.Data1 =3D CurrentFile->Name.Data= 1; + LocalEncapData->FvExtHeader->FvName.Data2 =3D CurrentFile->Name.Data= 2; + LocalEncapData->FvExtHeader->FvName.Data3 =3D CurrentFile->Name.Data= 3; + LocalEncapData->FvExtHeader->FvName.Data4[0] =3D CurrentFile->Name.D= ata4[0]; + LocalEncapData->FvExtHeader->FvName.Data4[1] =3D CurrentFile->Name.D= ata4[1]; + LocalEncapData->FvExtHeader->FvName.Data4[2] =3D CurrentFile->Name.D= ata4[2]; + LocalEncapData->FvExtHeader->FvName.Data4[3] =3D CurrentFile->Name.D= ata4[3]; + LocalEncapData->FvExtHeader->FvName.Data4[4] =3D CurrentFile->Name.D= ata4[4]; + LocalEncapData->FvExtHeader->FvName.Data4[5] =3D CurrentFile->Name.D= ata4[5]; + LocalEncapData->FvExtHeader->FvName.Data4[6] =3D CurrentFile->Name.D= ata4[6]; + LocalEncapData->FvExtHeader->FvName.Data4[7] =3D CurrentFile->Name.D= ata4[7]; + LocalEncapData->RightNode =3D NULL; + LocalEncapData->NextNode =3D NULL; + } + + if ( CurrentFile->Type =3D=3D EFI_FV_FILETYPE_RAW){ + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag){ + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, Era= sePolarity); + } + } else if( CurrentFile->Type =3D=3D EFI_FV_FILETYPE_FFS_PAD){ + //EFI_FV_FILETYPE_FFS_PAD + } else { + // + // All other files have sections + // + Status =3D 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 =3D 0; + Key =3D 0; + LocalEncapData =3D NULL; + CurrentFile =3D NULL; + FvHdr =3D (EFI_FIRMWARE_VOLUME_HEADER *)Fv; + + + Level +=3D 1; + *FvCount +=3D 1; + CurrentFv->FvLevel +=3D 1; + + Status =3D FvBufGetSize (Fv, &FvSize); + + ErasePolarity =3D (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_F= VB2_ERASE_POLARITY) ? TRUE : FALSE; + + Status =3D 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 =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvHdr->= HeaderLength); + + if (CurrentFv->FvHeader =3D=3D 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 =3D NULL; + CurrentFv->FvUiName =3D NULL; + + // + // Exist Extend FV header. + // + if (CurrentFv->FvHeader->ExtHeaderOffset !=3D 0){ + ExtHdrPtr =3D (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOff= set); + CurrentFv->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc= (ExtHdrPtr->ExtHeaderSize); + + if (CurrentFv->FvExtHeader =3D=3D 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->FvHe= ader->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize); + LibExtractFvUiName(CurrentFv->FvExtHeader, &CurrentFv->FvUiName); + } + } + + // + // Put encapsulate information into structure. + // + LocalEncapData =3D *CurrentFvEncapData; + if (LocalEncapData =3D=3D NULL && !IsChildFv) { + // + // First time in, the root FV + // + LocalEncapData =3D (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA= )); + CurrentFv->EncapData =3D LocalEncapData; + if (CurrentFv->EncapData =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + CurrentFv->EncapData->FvExtHeader =3D NULL; + CurrentFv->EncapData->Depex =3D NULL; + CurrentFv->EncapData->DepexLen =3D 0; + CurrentFv->EncapData->UiNameSize =3D 0; + CurrentFv->EncapData->Level =3D Level; + CurrentFv->EncapData->Type =3D FMMT_ENCAP_TREE_FV; + CurrentFv->EncapData->Data =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc = (sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + CurrentFv->EncapData->FvId =3D *FvCount; + + if (CurrentFv->EncapData->Data =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HE= ADER)); + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtH= eaderOffset !=3D 0) { + ExtHdrPtr =3D (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(C= urrentFv->EncapData->Data))->ExtHeaderOffset); + CurrentFv->EncapData->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADE= R *) malloc (ExtHdrPtr->ExtHeaderSize); + + if (CurrentFv->EncapData->FvExtHeader =3D=3D 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 =3D NULL; + CurrentFv->EncapData->RightNode =3D NULL; + } else if (LocalEncapData =3D=3D NULL) { + return EFI_ABORTED; + } else if (IsChildFv) { + + LocalEncapData =3D *CurrentFvEncapData; + while (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + } + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (ENC= AP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D FMMT_ENCAP_TREE_FV; + LocalEncapData->Data =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc (siz= eof (EFI_FIRMWARE_VOLUME_HEADER)); + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->Depex =3D NULL; + LocalEncapData->DepexLen =3D 0; + LocalEncapData->UiNameSize =3D 0; + LocalEncapData->FvId =3D *FvCount; + if (LocalEncapData->Data =3D=3D 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))->ExtHeade= rOffset !=3D 0) { + ExtHdrPtr =3D (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)= (LocalEncapData->Data))->ExtHeaderOffset); + LocalEncapData->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *)= malloc(ExtHdrPtr->ExtHeaderSize); + + if (LocalEncapData->FvExtHeader =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + + // + // Get the FV extended Header information + // + memcpy(LocalEncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIR= MWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr-= >ExtHeaderSize); + } + + LocalEncapData->NextNode =3D NULL; + LocalEncapData->RightNode =3D NULL; + + } + + + // + // Get the first file + // + Status =3D FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); + if (Status =3D=3D EFI_NOT_FOUND) { + CurrentFile =3D NULL; + } else if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the fir= st file in the FV image"); + return Status; + } + + while (CurrentFile !=3D NULL) { + + // + // Increment the number of files counter + // + NumberOfFiles++; + + // + // Store FFS file Header information + // + CurrentFv->FfsHeader[*FfsCount].Attributes =3D CurrentFile->Attr= ibutes; + CurrentFv->FfsHeader[*FfsCount].IntegrityCheck =3D CurrentFile->Inte= grityCheck; + CurrentFv->FfsHeader[*FfsCount].Name =3D CurrentFile->Name; + CurrentFv->FfsHeader[*FfsCount].Size[0] =3D CurrentFile->Size= [0]; + CurrentFv->FfsHeader[*FfsCount].Size[1] =3D CurrentFile->Size= [1]; + CurrentFv->FfsHeader[*FfsCount].Size[2] =3D CurrentFile->Size= [2]; + CurrentFv->FfsHeader[*FfsCount].State =3D CurrentFile->Stat= e; + CurrentFv->FfsHeader[*FfsCount].Type =3D CurrentFile->Type; + CurrentFv->FfsHeader[*FfsCount].ExtendedSize =3D CurrentFile->Exte= ndedSize; + CurrentFv->FfsAttuibutes[*FfsCount].Offset =3D Key - GetFfsFileLength = ((EFI_FFS_FILE_HEADER *) CurrentFile); + + CurrentFv->FfsAttuibutes[*FfsCount].FvLevel =3D CurrentFv->FvLevel; + if (CurrentFv->FvLevel > CurrentFv->MulFvLevel) { + CurrentFv->MulFvLevel =3D CurrentFv->FvLevel; + } + // + // Display info about this file + // + Status =3D 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 =3D FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); + if (Status =3D=3D EFI_NOT_FOUND) { + CurrentFile =3D NULL; + } else if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the n= ext file in the FV image"); + return Status; + } + } + + if (IsChildFv) { + if (CurrentFv->FvLevel > 1) { + CurrentFv->FvLevel -=3D 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 =3D ActualSize; + while ((OccupiedSize & (Alignment - 1)) !=3D 0) { + OccupiedSize++; + } + + return OccupiedSize; +} + + + +EFI_STATUS +LibDeleteAndRenameFfs( + IN CHAR8* DeleteFile, + IN CHAR8* NewFile +) +{ + CHAR8* SystemCommand; + CHAR8* TemDir; + SystemCommand =3D NULL; + + if (DeleteFile =3D=3D NULL || + NewFile =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Delete the file of the specified extract FFS file. + // + SystemCommand =3D malloc ( + strlen (DEL_STR) + + strlen (DeleteFile) + + 1 + ); + if (SystemCommand =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + DEL_STR, + DeleteFile + ); + + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + TemDir =3D 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 =3D malloc ( + strlen (COPY_STR) + + strlen (NewFile) + + strlen (DeleteFile) + + 1 + ); + if (SystemCommand =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + COPY_STR, + NewFile, + DeleteFile + ); + + if (system (SystemCommand) !=3D 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 !=3D '\0') { + *(UniString++) =3D (CHAR16) *(String++); + } + // + // End the UniString with a NULL. + // + *UniString =3D '\0'; +} + + +EFI_STATUS +LibCreateGuidedSectionOriginalData( + IN CHAR8* FileIn, + IN CHAR8* ToolName, + IN CHAR8* FileOut +) +{ + CHAR8* SystemCommandFormatString; + CHAR8* SystemCommand; + + SystemCommandFormatString =3D NULL; + SystemCommand =3D NULL; + + if (FileIn =3D=3D NULL || + ToolName =3D=3D NULL || + FileOut =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Delete the file of the specified extract FFS file. + // + SystemCommandFormatString =3D "%s -e \"%s\" -o \"%s\""; + + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (FileIn) + + strlen (ToolName) + + strlen (FileOut) + + 1 + ); + if (SystemCommand =3D=3D 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) !=3D 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 conver= ted 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 informat= ion. + + @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 =3D NULL; + + LocalStr =3D (CHAR8 *) malloc (1024 * 4); + + if (LocalStr =3D=3D NULL) { + printf ("Memory allocate error!\n"); + return EFI_OUT_OF_RESOURCES; + } + + memset (LocalStr, '\0', 1024 * 4); + + if (Attr =3D=3D 0 || InfFile =3D=3D 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 =3D TRUE \n", sizeof ("EFI_R= EAD_DISABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_ENABLED_CAP) { + strncat (LocalStr, "EFI_READ_ENABLED_CAP =3D TRUE \n", sizeof ("EFI_RE= AD_ENABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_STATUS) { + strncat (LocalStr, "EFI_READ_STATUS =3D TRUE \n", sizeof ("EFI_READ_ST= ATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) { + strncat (LocalStr, "EFI_WRITE_DISABLED_CAP =3D TRUE \n", sizeof ("EFI_= WRITE_DISABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) { + strncat (LocalStr, "EFI_WRITE_ENABLED_CAP =3D TRUE \n", sizeof ("EFI_W= RITE_ENABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_STATUS) { + strncat (LocalStr, "EFI_WRITE_STATUS =3D TRUE \n", sizeof ("EFI_WRITE_= STATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_CAP) { + strncat (LocalStr, "EFI_LOCK_CAP =3D TRUE \n", sizeof ("EFI_LOCK_CAP = =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_STATUS) { + strncat (LocalStr, "EFI_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_LOCK_ST= ATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_STICKY_WRITE) { + strncat (LocalStr, "EFI_STICKY_WRITE =3D TRUE \n", sizeof ("EFI_STICKY= _WRITE =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_MEMORY_MAPPED) { + strncat (LocalStr, "EFI_MEMORY_MAPPED =3D TRUE \n", sizeof ("EFI_MEMOR= Y_MAPPED =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_ERASE_POLARITY) { + strncat (LocalStr, "EFI_ERASE_POLARITY =3D 1 \n", sizeof ("EFI_ERASE_P= OLARITY =3D 1 \n")); + } + + if (Attr & EFI_FVB2_READ_LOCK_CAP) { + strncat (LocalStr, "EFI_READ_LOCK_CAP =3D TRUE \n", sizeof ("EFI_READ_= LOCK_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_LOCK_STATUS) { + strncat (LocalStr, "EFI_READ_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_RE= AD_LOCK_STATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_LOCK_CAP) { + strncat (LocalStr, "EFI_WRITE_LOCK_CAP =3D TRUE \n", sizeof ("EFI_WRIT= E_LOCK_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) { + strncat (LocalStr, "EFI_WRITE_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_W= RITE_LOCK_STATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_STATUS) { + strncat (LocalStr, "EFI_READ_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_RE= AD_LOCK_STATUS =3D TRUE \n")); + } + + // + // Alignment + // + if (Attr & EFI_FVB2_ALIGNMENT_1) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_1 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_2 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_4 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_8 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_16 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_32 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_64 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_128 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_256 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_512 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_1K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_2K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_4K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_8K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_16K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_32K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_64K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_128K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_256K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_512K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_1M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_2M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_4M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_8M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_16M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_32M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_64M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_128M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_256M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_512M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1G) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_1G =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2G) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_2G =3D TRUE \n")); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) !=3D (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 informat= ion. + + @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 =3D NULL; + TempStr =3D NULL; + + if (FvHeader =3D=3D NULL || InfFile =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // This section will not over 1024 bytes and each line will never over 1= 28 bytes. + // + LocalStr =3D (CHAR8 *) malloc (1024); + TempStr =3D (CHAR8 *) malloc (128); + + if (LocalStr =3D=3D NULL || + TempStr =3D=3D NULL ) { + if (LocalStr !=3D NULL) { + free (LocalStr); + } + if (TempStr !=3D NULL) { + free (TempStr); + } + printf ("Memory allocate error! \n"); + return EFI_OUT_OF_RESOURCES; + } + + BlockMap =3D FvHeader->BlockMap; + memset (LocalStr, '\0', 1024); + memset (TempStr, '\0', 128); + + strncat (LocalStr, "[options] \n", sizeof("[Options] \n")); + + + snprintf (TempStr, 128, "EFI_BLOCK_SIZE =3D 0x%x \n", BlockMap->Length); + strncat (LocalStr, TempStr, strlen(TempStr)); + + if (IsRootFv) { + snprintf (TempStr, 128, "EFI_NUM_BLOCKS =3D 0x%x \n", BlockMap->NumBloc= ks); + strncat (LocalStr, TempStr, strlen(TempStr)); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) !=3D (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 informat= ion + @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 =3D NULL; + + if (FfsName =3D=3D NULL || InfFile =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (strlen(FfsName) =3D=3D 0) { + return EFI_SUCCESS; + } + + LocalStr =3D (CHAR8 *) malloc (_MAX_PATH); + + if (LocalStr =3D=3D NULL) { + printf ("Memory allocate error! \n"); + return EFI_OUT_OF_RESOURCES; + } + + memset (LocalStr, '\0', _MAX_PATH); + + if (FirstIn) { + sprintf (LocalStr, "[files] \nEFI_FILE_NAME =3D %s \n", FfsName); + } else { + sprintf (LocalStr, "EFI_FILE_NAME =3D %s \n", FfsName); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) !=3D (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 =3D NULL; + SystemCommand =3D NULL; + strcpy(AlignmentStr,"1"); + // + // Call GenSec tool to generate FFS section. + // + + // + // -s SectionType. + // + if (Type !=3D 0) { + switch (Type) { + // + // Process compression section + // + case EFI_SECTION_COMPRESSION: + SystemCommandFormatString =3D "GenSec -s %s -c %s \"%s\" -o \"%s\= ""; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (mSectionTypeName[Type]) + + strlen (CompressType) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (SystemCommand =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenSec -s %s -c %s \"%s\" -o \"%s\"", + mSectionTypeName[Type], + CompressType, + InputFilePath, + OutputFilePath + ); + + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + // + // Process GUID defined section + // + case EFI_SECTION_GUID_DEFINED: + SystemCommandFormatString =3D "GenSec -s %s -g %s \"%s\" -o \"%s\"= -r %s -r %s -l %d"; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (mSectionTypeName[Type]) + + strlen (GuidToolGuid) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + strlen (mGuidSectionAttr[GuidAttr&0x01]) + + strlen (mGuidSectionAttr[GuidAttr&0x02]) + + 4 + + 1 + ); + if (SystemCommand =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + 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) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: + + SystemCommandFormatString =3D "GenSec -s %s \"%s\" -o \"%s\""; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (mSectionTypeName[Type]) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (SystemCommand =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NUL= L); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenSec -s %s \"%s\" -o \"%s\"", + mSectionTypeName[Type], + InputFilePath, + OutputFilePath + ); + + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + default: + Error ("FMMT", 0, 0003, "Please specify the section type while cal= l GenSec tool.", NULL); + return EFI_UNSUPPORTED; + } + } else { + // + // Create Dummy section. + // + file =3D fopen(InputFilePath, "rb"); + if (file =3D=3D 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) !=3D (size_t)(4)) { + fclose(file); + return EFI_ABORTED; + } + if (*(Buffer + 3) =3D=3D EFI_SECTION_FIRMWARE_VOLUME_IMAGE) { + // The Section Struct, if size is not 0xFFFF, the length is 4 + Position =3D 4; + // If Size is 0xFFFFFF then ExtendedSize contains the size of the se= ction + if ((*Buffer =3D=3D 0xFF) && (*(Buffer + 1) =3D=3D 0xFF) && (*(Buffe= r + 2) =3D=3D 0xFF)) { + Position =3D 8; + } + //Per EFI_FIRMWARE_VOLUME_HEADER struct, 0x2E bit is EFI_FVB_ATTRIBU= TES_2 attr + fseek(file, 0x2E + Position, SEEK_SET); + BitNum =3D fgetc(file); + AlignmentValue =3D 1 << (BitNum & 0x1F); + if (AlignmentValue >=3D 0x400){ + if (AlignmentValue >=3D 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 =3D "GenSec \"%s\" -o \"%s\" --sectionalign = %s"; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 4 + // Alignment maximum length + 1 + ); + if (SystemCommand =3D=3D 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) !=3D 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 fil= e. This option is required. + @param[in] OutputFilePath The created PI firmware file name. This opt= ion is required. + @param[in] BlockSize BlockSize is one HEX or DEC format value re= quired 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 =3D "8c8ce578-8a3d-4f1c-9935-896185c32dd3= "; + + if (IsLargeFile =3D=3D TRUE) { + FfsGuid =3D "5473c07a-3dcb-4dca-bd6f-1e9689e7349a"; + } + + SystemCommandFormatString =3D NULL; + SystemCommand =3D NULL; + + if (OutputFilePath =3D=3D NULL || + InfFilePath =3D=3D NULL ) { + return EFI_INVALID_PARAMETER; + } + + if (InfFilePath !=3D NULL) { + if (FvGuidName =3D=3D NULL) { + SystemCommandFormatString =3D "GenFv -i \"%s\" -g %s -o \"%s\""; + + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (InfFilePath) + + strlen (FfsGuid) + + strlen (OutputFilePath) + + 1 + ); + if (SystemCommand =3D=3D 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) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + + free(SystemCommand); + } else { + // + // Have FvGuidName in it. + // + SystemCommandFormatString =3D "GenFv -i \"%s\" -g %s -o \"%s\" --FvN= ameGuid %s"; + + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (InfFilePath) + + strlen (FfsGuid) + + strlen (OutputFilePath) + + strlen (FvGuidName) + + 1 + ); + if (SystemCommand =3D=3D 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) !=3D 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 =3D NULL; + + if (Guid =3D=3D NULL) { + printf ("The guid is NULL while convert guid to string! \n"); + return NULL; + } + + Buffer =3D (CHAR8 *) malloc (36 + 1); + + if (Buffer =3D=3D 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_FILET= YPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE, + EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APP= LICATION, 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 fil= e. This option is required. + @param[in] OutputFilePath The created PI firmware file name. This opt= ion 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 i= ndicate that the file may not be moved from its present location. + @param[in] SectionAlign FileAlign specifies FFS file alignment, whi= ch 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 =3D NULL; + SystemCommand =3D NULL; + GuidStr =3D NULL; + + GuidStr =3D LibFmmtGuidToStr(&FileGuid); + + if (GuidStr =3D=3D NULL) { + return EFI_ABORTED; + } + + + // + // -t Type + // -i InputFilePath + // -o OutPutFilePath + // -g FileGuid + // -x Fixed + // -n SectionAlign + // + + if (Fixed) { + SystemCommandFormatString =3D "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s= \" -a %s"; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (mFfsFileType[Type]) + + strlen (InputFilePath) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 4 + + 1 + ); + if (SystemCommand =3D=3D 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) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + } else { + SystemCommandFormatString =3D "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" = -a %s"; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen (mFfsFileType[Type]) + + strlen (InputFilePath) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 4 + + 1 + ); + if (SystemCommand =3D=3D 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) !=3D 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 =3D NULL; + OldFdFile =3D NULL; + NewFdDir =3D NULL; + OldFdDir =3D NULL; + Count =3D 0; + UseNewDirFlag =3D FALSE; + + if (OldFd =3D=3D NULL || + NewFd =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + + NewFdDir =3D getcwd (NULL, _MAX_PATH); + + Count =3D strlen(NewFdDir); + + if (strlen(NewFd) > Count) { + + do { + if (NewFdDir[Count-1] =3D=3D 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 =3D TRUE; + break; + } + + } while (Count !=3D 1); + + }else { + if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PAT= H -1) { + return EFI_ABORTED; + } + strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1); + strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1); + UseNewDirFlag =3D TRUE; + } + + if (UseNewDirFlag) { + NewFdFile =3D fopen (NewFdDir, "wb+"); + if (NewFdFile =3D=3D NULL) { + NewFdFile =3D fopen (NewFd, "wb+"); + } + } else { + NewFdFile =3D fopen (NewFd, "wb+"); + } + // support network path file + if (OldFd[0] =3D=3D '\\' && OldFd[1] =3D=3D '\\') { + OldFdFile =3D fopen (OldFd, "rb"); + } else { + UseNewDirFlag =3D FALSE; + + OldFdDir =3D getcwd (NULL, _MAX_PATH); + + Count =3D strlen(OldFdDir); + + if (strlen(OldFd) > Count) { + + do { + if (OldFdDir[Count-1] =3D=3D OldFd[Count-1]) { + Count--; + } else { + if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX= _PATH -1) { + if (NewFdFile !=3D 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 =3D TRUE; + break; + } + + } while (Count !=3D 1); + + }else { + if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PAT= H -1) { + if (NewFdFile !=3D 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 =3D TRUE; + } + + if (UseNewDirFlag) { + OldFdFile =3D fopen (OldFdDir, "rb+"); + if (OldFdFile =3D=3D NULL) { + OldFdFile =3D fopen (OldFd, "rb+"); + } + } else { + OldFdFile =3D fopen (OldFd, "rb+"); + } + } + + if (NewFdFile =3D=3D NULL) { + Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD = file."); + if (OldFdFile !=3D NULL) { + fclose (OldFdFile); + } + return EFI_ABORTED; + } + + if (OldFdFile =3D=3D NULL) { + Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD = file."); + if (NewFdFile !=3D NULL) { + fclose (NewFdFile); + } + return EFI_ABORTED; + } + + + fseek(OldFdFile,0,SEEK_SET); + fseek(OldFdFile,0,SEEK_END); + + FdLength =3D ftell(OldFdFile); + + fseek(OldFdFile,0,SEEK_SET); + fseek(NewFdFile,0,SEEK_SET); + + Buffer =3D malloc ((size_t)FdLength); + + if (Buffer =3D=3D NULL) { + fclose(OldFdFile); + fclose(NewFdFile); + return EFI_ABORTED; + } + + if (fread (Buffer, 1, (size_t) FdLength, OldFdFile) !=3D (size_t) FdLeng= th) { + 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) !=3D (size_t) FdLen= gth) { + 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 retur= n the combined string. + Like FileName =3D file1, Dir =3D c:\temp extend =3D txt, the output stri= ng 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 =3D NULL; + + if (FileName =3D=3D NULL) { + return NULL; + } + + if (Dir =3D=3D NULL || Extend =3D=3D NULL) { + return FileName; + } + + RetStr =3D (CHAR8 *) malloc (strlen (FileName) + + strlen (Dir) + + strlen (Extend) + + strlen ("%s%s.%s") + + 1); + if (RetStr =3D=3D 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 =3D NULL; + + + if (DirName =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (access (DirName, 0) =3D=3D -1){ + return EFI_SUCCESS; + } + + // + // Delete a directory and files in it. + // + + SystemCommand =3D malloc ( + strlen (RMDIR_STR) + + strlen (DirName) + + 1 + ); + if (SystemCommand =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + RMDIR_STR, + DirName + ); + + if (system (SystemCommand) !=3D 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 =3D NULL; + + TempDir =3D getcwd(NULL, _MAX_PATH); + if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MA= X_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] =3D 0; + strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1); + + + ExtFile =3D fopen(OutputExtFile, "wb+"); + if (ExtFile =3D=3D NULL) { + return EFI_ABORTED; + } + + if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) !=3D ExtPtr->ExtHe= aderSize) { + fclose(ExtFile); + return EFI_ABORTED; + } + + fclose(ExtFile); + + strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME =3D "); + 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 (Li= ne) - 1); + strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1); + Len =3D strlen(Line); + if (fwrite(Line, 1, Len, InfFile) !=3D 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 =3D NULL; + TemDir =3D NULL; + + + if (FileName =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // if the FileName is not in TemDir, we don't need to delete. + TemDir =3D getcwd (NULL, _MAX_PATH); + if (*(TemDir + strlen(TemDir) - 1) =3D=3D OS_SEP) { + *(TemDir + strlen(TemDir) - 1) =3D '\0'; + } + if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MA= X_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) =3D=3D NULL) { + return EFI_SUCCESS; + } + + // + // Delete a file + // + + SystemCommand =3D malloc ( + strlen (DEL_STR) + + strlen (FileName) + + 1 + ); + if (SystemCommand =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + DEL_STR, + FileName + ); + + if (system (SystemCommand) !=3D 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 =3D NULL; + TempFv =3D NULL; + EncapData1 =3D NULL; + EncapData2 =3D NULL; + + if (Fd =3D=3D NULL) { + return; + } + + CurrentFv =3D Fd->Fv; + + do { + TempFv =3D CurrentFv; + CurrentFv =3D CurrentFv->FvNext; + + free (TempFv->FvHeader); + + if (TempFv->FvExtHeader !=3D NULL) { + free (TempFv->FvExtHeader); + } + if (TempFv->FvUiName) { + free(TempFv->FvUiName); + } + + // + // Free encapsulate data; + // + EncapData1 =3D TempFv->EncapData; + + while (EncapData1 !=3D NULL) { + + EncapData2 =3D EncapData1; + EncapData1 =3D EncapData1->NextNode; + + if (EncapData2->Data !=3D NULL) { + free (EncapData2->Data); + } + if (EncapData2->FvExtHeader !=3D NULL) { + free(EncapData2->FvExtHeader); + } + free (EncapData2); + EncapData2 =3D NULL; + } + + EncapData1 =3D NULL; + + free (TempFv); + TempFv =3D NULL; + + } while (CurrentFv !=3D NULL); + + CurrentFv =3D NULL; + free (Fd); + Fd =3D 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 =3D NULL; + //CompressedFile =3D NULL; + //UnCompressedBuffer =3D NULL; + //CompressedBuffer =3D NULL; + //TempName =3D NULL; + //TemDir =3D NULL; + //UnCompressedSize =3D 0; + //CompressedSize =3D 0; + + if ( InputFileName =3D=3D NULL || + OutPutFileName =3D=3D NULL) { + printf ("Error while generate compressed section!\n"); + return EFI_INVALID_PARAMETER; + } + + if (CompressionType =3D=3D EFI_STANDARD_COMPRESSION) { + /* + + UnCompressFile =3D fopen (InputFileName, "rb"); + if (UnCompressFile =3D=3D NULL) { + printf ("Error while open file %s \n", InputFileName); + return EFI_ABORTED; + } + + TemDir =3D _getcwd (NULL, _MAX_PATH); + sprintf(TemDir, "%s\\%s", TemDir, TEMP_DIR_NAME); + + TempName=3D LibFilenameStrExtended (strrchr(CloneString (tmpnam (NULL)= ),'\\'), TemDir, "comp"); + + CompressedFile =3D fopen (TempName, "wb+"); + if (CompressedFile =3D=3D 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 =3D ftell(UnCompressFile); + + fseek(UnCompressFile,0,SEEK_SET); + + UnCompressedBuffer =3D malloc (UnCompressedSize); + + if (UnCompressedBuffer =3D=3D NULL) { + printf("Error while allocate memory! \n"); + return EFI_OUT_OF_RESOURCES; + } + + CompressedBuffer =3D malloc (UnCompressedSize); + + if (CompressedBuffer =3D=3D NULL) { + printf("Error while allocate memory! \n"); + return EFI_OUT_OF_RESOURCES; + } + + if (fread (UnCompressedBuffer, 1, (size_t) UnCompressedSize, UnCompres= sFile) =3D=3D (size_t) UnCompressedSize) { + CompressedSize =3D UnCompressedSize; + + Status =3D 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, CompressedFi= le) !=3D (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 =3D=3D EFI_NOT_COMPRESSED) { + + LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSI= ON, 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 =3D NULL; + UINT8 SectionHeader[4] =3D { 0x00, 0x00, 0x00, 0x0= 0 }; + UINT32 Id; + UINT32 SubFvId; + UINT32 header; + UINT8 AlignN; + UINT8 AlignV[1] =3D {0xFF}; + AlignN =3D 0; + Id =3D 0; + InputFileSize =3D 0; + EncapFvIndex =3D 0; + Index =3D 0; + OuterIndex =3D 0; + ParentType =3D 0; + ParentLevel =3D 0; + Type =3D 0; + Level =3D 0; + SubFvId =3D 0; + FfsFoundFlag =3D FALSE; + LocalEncapDataTemp =3D NULL; + LocalEncapDataNext =3D NULL; + ExtractionTool =3D NULL; + InputFileName =3D NULL; + OutputFileName =3D NULL; + IsLastLevelFfs =3D TRUE; + IsLeafFlagIgnore =3D FALSE; + FirstInFlag =3D TRUE; + FvGuidName =3D NULL; + OutputFileNameListFlag =3D TRUE; + IsLargeFile =3D FALSE; + OutputFileSize =3D 0; + LargeFileSize =3D 0x1000000; + + + OutputFileNameList =3D (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION)); + if (OutputFileNameList =3D=3D NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n= ", ""); + return EFI_OUT_OF_RESOURCES; + } + OutputFileNameList->FFSName =3D NULL; + OutputFileNameList->InFvId =3D 0; + OutputFileNameList->IsFFS =3D FALSE; + OutputFileNameList->ParentLevel =3D 0; + OutputFileNameList->Next =3D NULL; + OutputFileNameList->UiNameSize =3D 0; + OutputFileNameList->Depex =3D NULL; + OutputFileNameList->DepexLen =3D 0; + OutputFileNameList->FfsFoundFlag =3D FALSE; + + ChildFileNameList =3D (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION)); + if (ChildFileNameList =3D=3D NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n= ", ""); + return EFI_OUT_OF_RESOURCES; + } + ChildFileNameList->FFSName =3D NULL; + ChildFileNameList->InFvId =3D 0; + ChildFileNameList->ParentLevel =3D 0; + ChildFileNameList->Next =3D NULL; + ChildFileNameList->IsFFS =3D FALSE; + ChildFileNameList->UiNameSize =3D 0; + ChildFileNameList->Depex =3D NULL; + ChildFileNameList->DepexLen =3D 0; + ChildFileNameList->FfsFoundFlag =3D FALSE; + // + // Encapsulate from the lowest FFS file level. + // + LocalEncapData =3D CurrentEncapData; + if (LocalEncapData =3D=3D NULL) { + LocalEncapData =3D FvInFd->EncapData; + } + Level =3D LocalEncapData->Level; + Type =3D LocalEncapData->Type; + + if (CurrentEncapData =3D=3D NULL) { + LocalEncapData =3D FvInFd->EncapData; + while (LocalEncapData !=3D NULL) { + if (LocalEncapData->Type =3D=3D FMMT_ENCAP_TREE_FFS) { + LocalEncapDataTemp =3D LocalEncapData->RightNode; + while (LocalEncapDataTemp !=3D NULL) { + LocalEncapDataNext =3D LocalEncapDataTemp->NextNode; + if (LocalEncapDataNext !=3D NULL && LocalEncapDataNext->NextNo= de !=3D NULL) { + + LibEncapNewFvFile(FvInFd, TemDir, LocalEncapDataTemp, 1, &= ChildFileNameList); + ChildFileNameList->ParentLevel =3D LocalEncapDataTemp->Lev= el -1; + if (FvInFd->ChildFvFFS =3D=3D NULL) { + FvInFd->ChildFvFFS =3D ChildFileNameList; + } else { + NewFileNameList =3D FvInFd->ChildFvFFS; + while (NewFileNameList->Next !=3D NULL) { + NewFileNameList =3D NewFileNameList->Next; + } + NewFileNameList->Next =3D ChildFileNameList; + } + } + LocalEncapDataTemp =3D LocalEncapDataTemp->RightNode; + } + } + + if (LocalEncapData->Level > Level) { + if (LocalEncapData->Type =3D=3D FMMT_ENCAP_TREE_FFS) { + ParentLevel =3D Level; + ParentType =3D Type; + } + Level =3D LocalEncapData->Level; + Type =3D LocalEncapData->Type; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + } else { + LocalEncapData =3D CurrentEncapData; + while (LocalEncapData !=3D NULL) { + if (LocalEncapData->Level > Level) { + if (LocalEncapData->Type =3D=3D FMMT_ENCAP_TREE_FFS) { + ParentLevel =3D Level; + ParentType =3D Type; + } + Level =3D LocalEncapData->Level; + Type =3D LocalEncapData->Type; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + } + + do { + switch (ParentType) { + case FMMT_ENCAP_TREE_FV: + OutputFileNameListFlag =3D TRUE; + EncapFvStart =3D 0; + for(OuterIndex=3D0;OutputFileNameListFlag;OuterIndex++){ + // + // Generate FV.inf attributes. + // + InfFileName =3D LibFilenameStrExtended (strrchr(GenTempFile (),OS_= SEP), TemDir, "inf"); + FirstInFlag =3D TRUE; + + InfFile =3D fopen (InfFileName, "wt+"); + + if (InfFile =3D=3D 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 =3D=3D NULL) { + LocalEncapData =3D FvInFd->EncapData; + } else { + LocalEncapData =3D CurrentEncapData; + } + + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHea= derOffset !=3D 0) { + // + // FV GUID Name memory allocation + // + FvGuidName =3D (CHAR8 *) malloc (255); + + if (FvGuidName =3D=3D NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation fa= iled! \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 =3D NULL; + } + + + if (ParentLevel =3D=3D 1) { + Status =3D LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)= LocalEncapData->Data, InfFile, TRUE); + } else { + Status =3D LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)= LocalEncapData->Data, InfFile, FALSE); + } + + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "gen= erate FV INF file [Options] section failed."); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + Status =3D LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER = *)LocalEncapData->Data)->Attributes, InfFile); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Gen= erate FV header attribute failed"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (LocalEncapData->FvExtHeader !=3D NULL) { + Status =3D LibGenExtFile(LocalEncapData->FvExtHeader, InfFile); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Ge= nerate FV EXT header failed"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + FvGuidName =3D NULL; + } + + if (CurrentEncapData !=3D NULL) { + for (Index =3D 0; Index <=3D FvInFd->FfsNumbers; Index++) { + if ((memcmp(&FvInFd->FfsAttuibutes[Index].GuidName, &(Curr= entEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) =3D=3D 0)) { + SubFvId =3D Index; + break; + } + } + } + // + // Found FFSs from Fv structure. + // + FfsFoundFlag =3D FALSE; + IsRootFv =3D FALSE; + for (Index=3D0; Index <=3D FvInFd->FfsNumbers; Index++) { + if (OutputFileNameList !=3D NULL && OutputFileNameList->FFSNam= e !=3D NULL && OutputFileNameList->IsFFS =3D=3D FALSE){ + break; + } + if (OutputFileNameList !=3D NULL && OutputFileNameList->FFSNam= e !=3D NULL && OutputFileNameList->IsFFS =3D=3D TRUE){ + if (Index =3D=3D EncapFvIndex) { + if (FirstInFlag) { + Status =3D LibAddFfsFileToFvInf (OutputFileNam= eList->FFSName, InfFile, TRUE); + FirstInFlag =3D FALSE; + } else { + Status =3D LibAddFfsFileToFvInf (OutputFileNam= eList->FFSName, InfFile, FALSE); + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsula= te FD Image", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + } + } + + NewFileNameList =3D FvInFd->ChildFvFFS; + while (NewFileNameList !=3D NULL && NewFileNameList -> FFSName= !=3D NULL) { + if (NewFileNameList -> ParentLevel =3D=3D ParentLevel && I= ndex =3D=3D NewFileNameList->InFvId && NewFileNameList->FfsFoundFlag=3D=3DT= RUE) { + if (FirstInFlag) { + Status =3D LibAddFfsFileToFvInf (NewFileNameList->= FFSName, InfFile, TRUE); + FirstInFlag =3D FALSE; + } else { + Status =3D LibAddFfsFileToFvInf (NewFileNameList->= FFSName, InfFile, FALSE); + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate F= D Image", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + } + NewFileNameList =3D NewFileNameList->Next; + } + + if (FvInFd->FfsAttuibutes[Index].IsHandle=3D=3DTRUE) { + continue; + } + if (SubFvId > 0 && Index < SubFvId) { + continue; + } + + // + // For the last level FFS, the level below FFSs we should not ca= re the IsLeaf Flag. + // + if (IsLastLevelFfs) { + IsLeafFlagIgnore =3D TRUE; + } else { + IsLeafFlagIgnore =3D FvInFd->FfsAttuibutes[Index].IsLeaf; + } + + if (FvInFd->FfsAttuibutes[Index].Level >=3D ParentLevel + 1 && I= sLeafFlagIgnore) { + if (FirstInFlag) { + if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) { + FfsFoundFlag =3D TRUE; + Status =3D LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].Ff= sName, InfFile, TRUE); + FirstInFlag =3D FALSE; + FvInFd->FfsAttuibutes[Index].IsHandle=3DTRUE; + EncapFvStart =3D Index; + } + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Imag= e", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (Index =3D=3D 0) { + // Root FV need to include all FFS files. + IsRootFv =3D TRUE; + } + } else { + if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) { + FfsFoundFlag =3D TRUE; + Status =3D LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].Ff= sName, InfFile, FALSE); + FvInFd->FfsAttuibutes[Index].IsHandle=3DTRUE; + } + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Imag= e", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (Index =3D=3D 0) { + // Root FV need to include all FFS files. + IsRootFv =3D TRUE; + } + } + + + //avoid a FV contain too many ffs files + if ((!IsRootFv) && (FvInFd->FfsAttuibutes[Index].FvLevel <=3D F= vInFd->MulFvLevel) && (FvInFd->FfsAttuibutes[Index+1].FvLevel <=3D FvInFd->= MulFvLevel) && + (FvInFd->FfsAttuibutes[Index].FvLevel !=3D FvInFd->FfsAttui= butes[Index+1].FvLevel) && (ParentLevel !=3D 1) && (FvInFd->FfsAttuibutes[I= ndex].Level !=3D FvInFd->FfsAttuibutes[Index+1].Level) && + FvInFd->FfsAttuibutes[Index].Level !=3D 0xFF && FvInFd->Ffs= Attuibutes[Index+1].Level !=3D 0xFF && FvInFd->FfsAttuibutes[Index+1].Level= !=3D 0x0){ + FvInFd->FfsAttuibutes[Index].Level =3D 0; + break; + }else{ + if (FvInFd->FfsAttuibutes[Index].Level !=3D 0xFF){ + FvInFd->FfsAttuibutes[Index].Level =3D 0; + } + } + + } + } + // The Fv may has multiple level (> 2), when it is in the FvLevel = =3D=3D 2, we set the IsLastLevelFfs Flag + if (Index <=3DFvInFd->FfsNumbers && FvInFd->FfsAttuibutes[Index].Fv= Level <=3D FvInFd->MulFvLevel) { + if (FvInFd->FfsAttuibutes[Index].FvLevel =3D=3D 2) { + IsLastLevelFfs =3D FALSE; + } + } + if (!FfsFoundFlag){ + OutputFileNameListFlag =3D FALSE; + if (OuterIndex > 0){ + fclose (InfFile); + break; + } + } + // + // Create FV + // + fclose (InfFile); + + EncapFvIndex =3D EncapFvStart; + + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "FV"); + + Status =3D LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileNam= e, FvGuidName, IsLargeFile); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Gen= erate FV failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + OutputFileNameList->FFSName =3D (char *)malloc(strlen(OutputFileName)+= 1); + if (OutputFileNameList->FFSName =3D=3D NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! = \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, st= rlen(OutputFileName)+1); + if (CurrentEncapData !=3D NULL) { + OutputFileNameList->InFvId =3D EncapFvIndex; + if (EncapFvIndex > 0) { + memcpy(OutputFileNameList->UiName,FvInFd->FfsAttuibutes[EncapF= vIndex - 1].UiName, FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize); + OutputFileNameList->UiNameSize =3D FvInFd->FfsAttuibutes[Encap= FvIndex - 1].UiNameSize; + OutputFileNameList->Depex =3D FvInFd->FfsAttuibutes[EncapFvInd= ex - 1].Depex; + OutputFileNameList->DepexLen =3D FvInFd->FfsAttuibutes[EncapFv= Index - 1].DepexLen; + OutputFileNameList->FfsFoundFlag =3D FfsFoundFlag; + } + } + } + break; + case FMMT_ENCAP_TREE_FFS: + + while(OutputFileNameList!=3D NULL && OutputFileNameList->FFSName != =3D NULL){ + InputFileName =3D OutputFileNameList->FFSName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile ()= , OS_SEP), TemDir, "ffs"); + LocalEncapData =3D CurrentEncapData; + if (LocalEncapData =3D=3D NULL) { + LocalEncapData =3D FvInFd->EncapData; + } + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + for(;LocalEncapData->NextNode !=3D NULL;) { + if(LocalEncapData->FvExtHeader !=3D NULL) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + if (LocalEncapData->FvExtHeader =3D=3D NULL) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "G= enerate FFS file failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + + if (OutputFileNameList->UiNameSize > 0) { + TmpFileName =3D LibFilenameStrExtended(strrchr(GenTempFile (= ), OS_SEP), TemDir, "tmp"); + TmpFile =3D fopen(TmpFileName, "wb+"); + if (TmpFile =3D=3D NULL) { + Error("FMMT", 0, 0004, "Could not open tmp file %s to sto= re UI section information! \n", ""); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + header =3D (OutputFileNameList->UiNameSize+4) | (EFI_SECTION_= USER_INTERFACE << 24); + Index =3D 0; + while (header) { + SectionHeader[Index] =3D header % 0x100; + header /=3D 0x100; + Index ++; + } + InputFile =3D fopen(InputFileName, "rb+"); + if (InputFile =3D=3D 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 =3D ftell(InputFile); + fseek(InputFile, 0, SEEK_SET); + + Buffer =3D malloc(InputFileSize+OutputFileNameList->UiNameSiz= e+4); + memcpy(Buffer, (CHAR16 *)SectionHeader, 4); + memcpy(Buffer + 4, (CHAR16 *)(OutputFileNameList->UiName), Ou= tputFileNameList->UiNameSize); + if (fread(Buffer+4+OutputFileNameList->UiNameSize, 1, InputFi= leSize, InputFile) !=3D InputFileSize) { + Error("FMMT", 0, 0004, "Could not open sec file %s to add U= I section information! \n", ""); + fclose(TmpFile); + fclose(InputFile); + free(Buffer); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fwrite(Buffer, 1, InputFileSize + OutputFileNameList->UiNameS= ize + 4, TmpFile); + free(Buffer); + fclose(TmpFile); + fclose(InputFile); + InputFileName =3D TmpFileName; + } + if (OutputFileNameList->DepexLen > 0) { + TmpFileName =3D LibFilenameStrExtended(strrchr(GenTempFile (= ), OS_SEP), TemDir, "tmp"); + TmpFile =3D fopen(TmpFileName, "wb+"); + if (TmpFile =3D=3D NULL) { + Error("FMMT", 0, 0004, "Could not open tmp file %s to st= ore Depex section information! \n", ""); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + InputFile =3D fopen(InputFileName, "rb+"); + if (InputFile =3D=3D 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 =3D ftell(InputFile); + fseek(InputFile, 0, SEEK_SET); + // make sure the section is 4 byte align + if (OutputFileNameList->DepexLen % 4 !=3D 0) { + AlignN =3D 4 - OutputFileNameList->DepexLen % 4; + } + Buffer =3D malloc(InputFileSize + OutputFileNameList->DepexL= en + AlignN); + memcpy(Buffer, OutputFileNameList->Depex, OutputFileNameList= ->DepexLen); + if (AlignN !=3D 0) { + for (Index =3D 0; Index < AlignN; Index ++) { + memcpy(Buffer + OutputFileNameList->DepexLen + Index= , AlignV, 1); + } + } + if (fread(Buffer + OutputFileNameList->DepexLen + AlignN, 1,= InputFileSize, InputFile) !=3D InputFileSize) { + Error("FMMT", 0, 0004, "Could not open sec file %s to ad= d Depex section information! \n", ""); + fclose(TmpFile); + fclose(InputFile); + free(Buffer); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fwrite(Buffer, 1, InputFileSize + OutputFileNameList->DepexL= en + AlignN, TmpFile); + free(Buffer); + fclose(TmpFile); + fclose(InputFile); + InputFileName =3D TmpFileName; + } + for (Id =3D FvInFd->FfsNumbers; Id <=3D FvInFd->FfsNumbers; Id--)= { + if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(LocalEncap= Data->FvExtHeader->FvName), sizeof(EFI_GUID)) =3D=3D 0)){ + if (access(FvInFd->FfsAttuibutes[Id].FfsName, 0) !=3D -1)= { + Status =3D LibFmmtDeleteFile(FvInFd->FfsAttuibutes[Id= ].FfsName); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate F= D Image", "Delete the specified file failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + memset(FvInFd->FfsAttuibutes[Id].FfsName, '\0', _MAX_= PATH); + FvInFd->FfsAttuibutes[Id].Level =3D 0xFF; + break; + } + } + } + if (LocalEncapData->NextNode !=3D NULL) { + LocalEncapDataTemp =3D LocalEncapData->NextNode; + if ((LocalEncapDataTemp->Type =3D=3D FMMT_ENCAP_TREE_GUIDED_S= ECTION) || (LocalEncapDataTemp->Type =3D=3D FMMT_ENCAP_TREE_COMPRESS_SECTIO= N)) { + Status =3D LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMW= ARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeade= r->FvName, FALSE, "1"); + } + else{ + Status =3D LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMW= ARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeade= r->FvName, FALSE, FvInFd->AlignmentStr); + } + } + else{ + Status =3D LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_= VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->F= vName, FALSE, FvInFd->AlignmentStr); + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Gener= ate FFS file failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + free(LocalEncapData->FvExtHeader); + LocalEncapData->FvExtHeader =3D NULL; + OutputFileNameList->FFSName =3D (char *)malloc(strlen(OutputFileName= )+1); + if (OutputFileNameList->FFSName =3D=3D NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation fail= ed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, = strlen(OutputFileName)+1); + OutputFileNameList->IsFFS =3D TRUE; + if (OutputFileNameList->Next =3D=3D NULL){ + break; + } + OutputFileNameList =3D OutputFileNameList->Next; + } + break; + case FMMT_ENCAP_TREE_GUIDED_SECTION: + while(OutputFileNameList!=3D NULL && OutputFileNameList->FFSName != =3D NULL){ + // + // Create the guided section original data, do compress operation. + // + InputFileName =3D OutputFileNameList->FFSName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "compressed"); + + // + // Use the guided section header guid to find out compress applica= tion name. + // + LocalEncapData =3D CurrentEncapData; + if (LocalEncapData =3D=3D NULL) { + LocalEncapData =3D FvInFd->EncapData; + } + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + ExtractionTool =3D + LookupGuidedSectionToolPath ( + mParsedGuidedSectionTools, + (EFI_GUID *)LocalEncapData->Data + ); + GuidDataOffset =3D *(UINT16 *) ((UINT8 *) LocalEncapData->Data + s= izeof (EFI_GUID)); + GuidAttributes =3D *(UINT16 *) ((UINT8 *) LocalEncapData->Data + s= izeof (EFI_GUID) + sizeof (UINT16)); + + Status =3D LibCreateGuidedSectionOriginalData (InputFileName, Extr= actionTool, OutputFileName); + + if (EFI_ERROR (Status) || GuidDataOffset < sizeof (EFI_GUID_DEFINE= D_SECTION)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Com= press guided data failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + GuidDataOffset =3D GuidDataOffset - sizeof (EFI_GUID_DEFINED_SECTI= ON); + InputFileName =3D OutputFileName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "guided"); + + Status =3D LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECT= ION_GUID_DEFINED, OutputFileName, NULL, NULL, LibFmmtGuidToStr((EFI_GUID *)= LocalEncapData->Data), GuidDataOffset, GuidAttributes, NULL); + OutFile =3D fopen(OutputFileName, "rb+"); + if (OutFile =3D=3D 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 =3D ftell(OutFile); + fclose(OutFile); + if (OutputFileSize > LargeFileSize) { + IsLargeFile =3D TRUE; + } + OutputFileNameList->FFSName =3D (char *)malloc(strlen(OutputFileName)+= 1); + if (OutputFileNameList->FFSName =3D=3D NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! = \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, st= rlen(OutputFileName)+1); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Gen= erate guided section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (OutputFileNameList->Next =3D=3D NULL){ + break; + } + OutputFileNameList =3D OutputFileNameList->Next; + } + break; + case FMMT_ENCAP_TREE_COMPRESS_SECTION: + while(OutputFileNameList!=3D NULL && OutputFileNameList->FFSName != =3D NULL){ + InputFileName =3D OutputFileNameList->FFSName; + + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile ()= , OS_SEP), TemDir, "comsec"); + LocalEncapData =3D CurrentEncapData; + if (LocalEncapData =3D=3D NULL) { + LocalEncapData =3D FvInFd->EncapData; + } + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + Status =3D LibGenCompressedSection (InputFileName, OutputFileNam= e, *(UINT8 *)(LocalEncapData->Data)); + OutputFileNameList->FFSName =3D (char *)malloc(strlen(OutputFileName= )+1); + if (OutputFileNameList->FFSName =3D=3D 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", "G= enerate compressed section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (OutputFileNameList->Next =3D=3D NULL){ + break; + } + OutputFileNameList =3D OutputFileNameList->Next; + } + break; + case FMMT_ENCAP_TREE_FV_SECTION: + while(OutputFileNameList!=3D NULL && OutputFileNameList->FFSName != =3D NULL){ + InputFileName =3D OutputFileNameList->FFSName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "sec"); + + Status =3D LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECT= ION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, 0, 0, NULL); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Gen= erate FV section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + InputFileName =3D OutputFileName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "sec"); + + // + // Make it alignment. + // + Status =3D LibCreateFfsSection(FvInFd, InputFileName, NULL, 0, Out= putFileName, NULL, NULL, NULL, 0, 0, NULL); + OutFile =3D fopen(OutputFileName, "rb+"); + if (OutFile =3D=3D 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 =3D ftell(OutFile); + fclose(OutFile); + if (OutputFileSize > LargeFileSize) { + IsLargeFile =3D TRUE; + } + + OutputFileNameList->FFSName =3D (char *)malloc(strlen(OutputFileName)+= 1); + if (OutputFileNameList->FFSName =3D=3D NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! = \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, st= rlen(OutputFileName)+1); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Gen= erate FV section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (OutputFileNameList->Next =3D=3D NULL){ + break; + } + OutputFileNameList =3D OutputFileNameList->Next; + } + break; + default: + for (Id =3D FvInFd->FfsNumbers; Id <=3D FvInFd->FfsNumbers; Id--) { + if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(CurrentEnca= pData->FvExtHeader->FvName), sizeof(EFI_GUID)) =3D=3D 0)){ + FvInFd->FfsAttuibutes[Id].IsHandle =3D TRUE; + memcpy(OutputFileNameList->UiName, FvInFd->FfsAttuibutes[I= d].UiName, FvInFd->FfsAttuibutes[Id].UiNameSize); + OutputFileNameList->UiNameSize =3D FvInFd->FfsAttuibutes[I= d].UiNameSize; + OutputFileNameList->FFSName =3D FvInFd->FfsAttuibutes[Id].= FfsName; + OutputFileNameList->Depex =3D FvInFd->FfsAttuibutes[Id].De= pex; + OutputFileNameList->DepexLen =3D FvInFd->FfsAttuibutes[Id]= .DepexLen; + OutputFileNameList->FfsFoundFlag =3D TRUE; + OutputFileNameList->IsFFS =3D TRUE; + OutputFileNameList->InFvId =3D Id; + *OutputFile =3D OutputFileNameList; + return EFI_SUCCESS; + } + } + } + + if (CurrentEncapData =3D=3D NULL) { + LocalEncapData =3D FvInFd->EncapData; + } else { + if (OutputFileNameList !=3D NULL && OutputFileNameList->FFSName != =3D NULL && OutputFileNameList->IsFFS =3D=3D TRUE) { + *OutputFile =3D OutputFileNameList; + return EFI_SUCCESS; + } + LocalEncapData =3D CurrentEncapData; + } + ParentLevel -=3D 1; + + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + LocalEncapDataTemp =3D LocalEncapData->NextNode; + if ((LocalEncapDataTemp !=3D NULL) && (LocalEncapDataTemp->Level = =3D=3D ParentLevel)) { + ParentType =3D LocalEncapDataTemp->Type; + break; + } + ParentType =3D LocalEncapData->Type; + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + } while (ParentLevel !=3D Level_Break); + + *OutputFile =3D OutputFileNameList; + return EFI_SUCCESS; + +} + +EFI_STATUS +LibFindFvInEncapData ( + ENCAP_INFO_DATA *EncapData, + UINT8 *Index +) +{ + ENCAP_INFO_DATA *LocalEncapData; + LocalEncapData =3D EncapData; + if (LocalEncapData =3D=3D NULL) { + Error("FMMT", 0, 0005, "error while find FV in Encapulate buffer", "In= valid parameters."); + return EFI_INVALID_PARAMETER; + } + while (LocalEncapData !=3D NULL) { + if (LocalEncapData->RightNode !=3D NULL) { + LibFindFvInEncapData (LocalEncapData->RightNode, Index); + } + if (LocalEncapData->Type =3D=3D FMMT_ENCAP_TREE_FV) { + (*Index)++; + } + LocalEncapData =3D 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 =3D 0; + FvIndex2 =3D 0; + FvFoundFlag =3D FALSE; + FvGuidName =3D NULL; + LocalEncapDataNext =3D NULL; + LocalEncapDataRight =3D NULL; + + if (FdData =3D=3D NULL || FvId =3D=3D NULL || FvInFd =3D=3D NULL || FdDa= ta->Fv =3D=3D NULL) { + Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid paramete= rs."); + return EFI_INVALID_PARAMETER; + } + + *FvInFd =3D FdData->Fv; + + if (strlen(FvId) < 3) { + Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, pl= ease double check the FvId. You can use view operate to get the FvId inform= ation!"); + return EFI_ABORTED; + } + + FvGuidName =3D (CHAR8 *) malloc (255); + if (FvGuidName =3D=3D NULL) { + Error ("FMMT", 0, 0005, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + memset(FvGuidName, '\0', 255); + LocalEncapData =3D NULL; + + if (strlen(FvId) =3D=3D 36) { + while (FvInFd !=3D NULL) { + if (((*FvInFd)->FvExtHeader) !=3D 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) =3D=3D 0) { + FvId =3D (*FvInFd)->FvName; + break; + } + } + if ((*FvInFd)->MulFvLevel > 1) { + LocalEncapData =3D (*FvInFd) -> EncapData; + LocalEncapData =3D LocalEncapData->NextNode; + while (LocalEncapData !=3D NULL) { + if (LocalEncapData->RightNode !=3D NULL) { + LocalEncapDataRight =3D LocalEncapData->RightNode; + while (LocalEncapDataRight !=3DNULL) { + if (LocalEncapDataRight->NextNode !=3D NULL) { + LocalEncapDataNext =3D LocalEncapDataRight->NextNode; + while (LocalEncapDataNext !=3D NULL) { + if (LocalEncapDataNext->Type =3D=3D FMMT_ENCAP_TREE_FV) { + if (LocalEncapDataNext->FvExtHeader !=3D NULL) { + sprintf( + FvGuidName, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02= X", + 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) =3D=3D 0) + { + sprintf(FvId, "%s%d", "FV", LocalEncapDataNext= ->FvId - 1); + break; + } + + } + } + LocalEncapDataNext =3D LocalEncapDataNext->NextNode; + } + } + LocalEncapDataRight =3D LocalEncapDataRight->RightNode; + } + } + if (LocalEncapData->Type =3D=3D FMMT_ENCAP_TREE_FV) { + if (LocalEncapData->FvExtHeader !=3D 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) =3D=3D 0) { + sprintf(FvId, "%s%d", "FV", LocalEncapData->FvId - 1); + break; + } + } + } + LocalEncapData =3D LocalEncapData->NextNode; + } + } + if ((*FvInFd)->FvNext =3D=3D 0) { + break; + } + *FvInFd =3D (*FvInFd)->FvNext; + } + } + *FvInFd =3D FdData->Fv; + FvIndex1 =3D (UINT8) atoi (FvId + 2); + + while (FvInFd !=3D NULL) { + if (((*FvInFd)->FvName) !=3D NULL) { + FvIndex2 =3D (UINT8) atoi ((*FvInFd)->FvName + 2); + LocalEncapData =3D (*FvInFd)->EncapData; + LibFindFvInEncapData (LocalEncapData, &FvIndex2); + + if ((FvIndex2 - 1 >=3D FvIndex1)) { + FvFoundFlag =3D TRUE; + break; + } + if ((*FvInFd)->FvNext =3D=3D 0) { + break; + } + } + *FvInFd =3D (*FvInFd)->FvNext; + } + if (FvGuidName !=3D 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, pl= ease double check the FvId. You can use view operate to get the FvId inform= ation!"); + 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] =3D { + "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 =3D NULL; + FirstGuidTool =3D NULL; + LastGuidTool =3D NULL; + NewGuidTool =3D NULL; + Index =3D 0; + + for (Index =3D 0; Index < BUILD_IN_TOOL_COUNT; Index++) { + Tool =3D SplitStringByWhitespace (PreDefinedGuidedTool[Index]); + if ((Tool !=3D NULL) && + (Tool->Count =3D=3D 3) + ) { + Status =3D StringToGuid (Tool->Strings[0], &Guid); + if (!EFI_ERROR (Status)) { + NewGuidTool =3D malloc (sizeof (GUID_SEC_TOOL_ENTRY)); + if (NewGuidTool !=3D NULL) { + memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid)); + NewGuidTool->Name =3D CloneString(Tool->Strings[1]); + NewGuidTool->Path =3D CloneString(Tool->Strings[2]); + NewGuidTool->Next =3D NULL; + } else { + printf ("Error while allocate resource! \n"); + FreeStringList (Tool); + return NULL; + } + if (FirstGuidTool =3D=3D NULL) { + FirstGuidTool =3D NewGuidTool; + } else { + LastGuidTool->Next =3D NewGuidTool; + } + LastGuidTool =3D NewGuidTool; + } + } else { + fprintf (stdout, "Error"); + } + if (Tool !=3D NULL) { + FreeStringList (Tool); + Tool =3D NULL; + } + } + return FirstGuidTool; +} diff --git a/Platform/Intel/Tools/FMMT/GNUmakefile b/Platform/Intel/Tools/F= MMT/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.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +MAKEROOT ?=3D $(EDK_TOOLS_PATH)/Source/C + +APPNAME =3D FMMT + +LIBS =3D -lCommon + +OBJECTS =3D 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.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common + +APPNAME =3D FMMT + +LIBS =3D $(LIB_PATH)\Common.lib + +OBJECTS =3D 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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Rebase.h" +#include +#include +#ifdef __GNUC__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#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 imag= e. + +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 im= age. +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 =3D 0; + MemoryImagePointer =3D NULL; + TEImageHeader =3D NULL; + ImgHdr =3D NULL; + SectionHeader =3D NULL; + Cptr =3D NULL; + PeFile =3D NULL; + PeFileBuffer =3D NULL; + + // + // Don't need to relocate image when BaseAddress is zero and no ForceReb= ase Flag specified. + // + if (BaseAddress =3D=3D 0) { + return EFI_SUCCESS; + } + + XipBase =3D 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 =3D GetFfsHeaderLength(FfsFile); + // + // Rebase each PE32 section + // + Status =3D EFI_SUCCESS; + for (Index =3D 1;; Index++) { + // + // Init Value + // + NewPe32BaseAddress =3D 0; + + // + // Find Pe Image + // + Status =3D GetSectionByType(FfsFile, EFI_SECTION_PE32, Index, &Current= Pe32Section); + if (EFI_ERROR(Status)) { + break; + } + CurSecHdrSize =3D GetSectionHeaderLength(CurrentPe32Section.CommonHead= er); + + // + // Initialize context + // + memset(&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle =3D (VOID *)((UINTN)CurrentPe32Section.Pe32Section= + CurSecHdrSize); + ImageContext.ImageRead =3D (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRea= d; + Status =3D PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and th= e return status is %x", FileName, (int)Status); + return Status; + } + + //if ((ImageContext.Machine =3D=3D EFI_IMAGE_MACHINE_ARMT) || + // (ImageContext.Machine =3D=3D EFI_IMAGE_MACHINE_AARCH64)) { + // mArm =3D TRUE; + //} + + // + // Keep Image Context for PE image in FV + // + memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext)); + + // + // Get File PdbPointer + // + PdbPointer =3D PeCoffLoaderGetPdbPointer(ImageContext.Handle); + if (PdbPointer =3D=3D NULL) { + PdbPointer =3D FileName; + } + + // + // Get PeHeader pointer + // + ImgHdr =3D (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)CurrentPe32Secti= on.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 !=3D ImgHdr->Pe32.= OptionalHeader.FileAlignment)) { + // + // Xip module has the same section alignment and file alignment. + // + Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignm= ent 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 lon= g.", FileName); + return EFI_ABORTED; + } + strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1); + PeFileName[MAX_LONG_FILE_PATH - 1] =3D 0; + Cptr =3D PeFileName + strlen(PeFileName); + while (*Cptr !=3D '.') { + Cptr--; + } + if (*Cptr !=3D '.') { + Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc secti= on.", FileName); + return EFI_ABORTED; + } + else { + *(Cptr + 1) =3D 'e'; + *(Cptr + 2) =3D 'f'; + *(Cptr + 3) =3D 'i'; + *(Cptr + 4) =3D '\0'; + } + LongFilePathName =3D LongFilePath(PeFileName); + if (LongFilePathName =3D=3D NULL) { + Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for = file %s.", FileName); + return EFI_ABORTED; + } + PeFile =3D fopen(LongFilePathName, "rb"); + if (PeFile =3D=3D NULL) { + Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc sectio= n.", FileName); + //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc se= ction.", FileName); + //return EFI_ABORTED; + break; + } + // + // Get the file size + // + PeFileSize =3D _filelength(fileno(PeFile)); + PeFileBuffer =3D (UINT8 *)malloc(PeFileSize); + if (PeFileBuffer =3D=3D 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 =3D PeFileBuffer; + Status =3D PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s an= d the return status is %x", FileName, (int)Status); + return Status; + } + ImageContext.RelocationsStripped =3D FALSE; + } + + NewPe32BaseAddress =3D XipBase + (UINTN)CurrentPe32Section.Pe32Secti= on + 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 !=3D ImgHdr->Pe32.= OptionalHeader.FileAlignment)) { + // + // Xip module has the same section alignment and file alignment. + // + Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignm= ent do not match : %s.", FileName); + return EFI_ABORTED; + } + NewPe32BaseAddress =3D XipBase + (UINTN)CurrentPe32Section.Pe32Secti= on + 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 =3D (UINT8 *)malloc((UINTN)ImageContext.ImageSize += ImageContext.SectionAlignment); + if (MemoryImagePointer =3D=3D NULL) { + Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on reba= se of %s", FileName); + return EFI_OUT_OF_RESOURCES; + } + memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + = ImageContext.SectionAlignment); + ImageContext.ImageAddress =3D ((UINTN)MemoryImagePointer + ImageContex= t.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1)); + + Status =3D 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 =3D NewPe32BaseAddress; + Status =3D PeCoffLoaderRelocateImage(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on reba= se of %s", FileName); + free((VOID *)MemoryImagePointer); + return Status; + } + + // + // Copy Relocated data to raw image file. + // + SectionHeader =3D (EFI_IMAGE_SECTION_HEADER *)( + (UINTN)ImgHdr + + sizeof (UINT32)+ + sizeof (EFI_IMAGE_FILE_HEADER)+ + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + + for (Index =3D 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; In= dex++, SectionHeader++) { + CopyMem( + (UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionH= eader->PointerToRawData, + (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualA= ddress), + SectionHeader->SizeOfRawData + ); + } + + free((VOID *)MemoryImagePointer); + MemoryImagePointer =3D NULL; + if (PeFileBuffer !=3D NULL) { + free(PeFileBuffer); + PeFileBuffer =3D NULL; + } + + // + // Update Image Base Address + // + if (ImgHdr->Pe32.OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPTIONAL_HDR= 32_MAGIC) { + ImgHdr->Pe32.OptionalHeader.ImageBase =3D (UINT32)NewPe32BaseAddress; + } + else if (ImgHdr->Pe32Plus.OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPT= IONAL_HDR64_MAGIC) { + ImgHdr->Pe32Plus.OptionalHeader.ImageBase =3D NewPe32BaseAddress; + } + else { + Error(NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE= 32 image %s", + ImgHdr->Pe32.OptionalHeader.Magic, + FileName + ); + return EFI_ABORTED; + } + + // + // Now update file checksum + // + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState =3D FfsFile->State; + FfsFile->IntegrityCheck.Checksum.File =3D 0; + FfsFile->State =3D 0; + FfsFile->IntegrityCheck.Checksum.File =3D CalculateChecksum8( + (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize), + GetFfsFileLength(FfsFile) - FfsHeaderSize + ); + FfsFile->State =3D SavedState; + } + + } + + if (FfsFile->Type !=3D EFI_FV_FILETYPE_SECURITY_CORE && + FfsFile->Type !=3D EFI_FV_FILETYPE_PEI_CORE && + FfsFile->Type !=3D EFI_FV_FILETYPE_PEIM && + FfsFile->Type !=3D EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER && + FfsFile->Type !=3D EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE + ) { + // + // Only Peim code may have a TE section + // + return EFI_SUCCESS; + } + + // + // Now process TE sections + // + for (Index =3D 1;; Index++) { + NewPe32BaseAddress =3D 0; + + // + // Find Te Image + // + Status =3D GetSectionByType(FfsFile, EFI_SECTION_TE, Index, &CurrentPe= 32Section); + if (EFI_ERROR(Status)) { + break; + } + + CurSecHdrSize =3D GetSectionHeaderLength(CurrentPe32Section.CommonHead= er); + + // + // Calculate the TE base address, the FFS file base plus the offset of= the TE section less the size stripped off + // by GenTEImage + // + TEImageHeader =3D (EFI_TE_IMAGE_HEADER *)((UINT8 *)CurrentPe32Section.= Pe32Section + CurSecHdrSize); + + // + // Initialize context, load image info. + // + memset(&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle =3D (VOID *)TEImageHeader; + ImageContext.ImageRead =3D (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRea= d; + Status =3D PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and th= e return status is %x", FileName, (int)Status); + return Status; + } + + //if ((ImageContext.Machine =3D=3D EFI_IMAGE_MACHINE_ARMT) || + // (ImageContext.Machine =3D=3D EFI_IMAGE_MACHINE_AARCH64)) { + // mArm =3D TRUE; + //} + + // + // Keep Image Context for TE image in FV + // + memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext)); + + // + // Get File PdbPointer + // + PdbPointer =3D PeCoffLoaderGetPdbPointer(ImageContext.Handle); + if (PdbPointer =3D=3D NULL) { + PdbPointer =3D FileName; + } + // + // Set new rebased address. + // + NewPe32BaseAddress =3D 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 relo= c 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] =3D 0; + Cptr =3D PeFileName + strlen(PeFileName); + while (*Cptr !=3D '.') { + Cptr--; + } + + if (*Cptr !=3D '.') { + Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section= .", FileName); + return EFI_ABORTED; + } + else { + *(Cptr + 1) =3D 'e'; + *(Cptr + 2) =3D 'f'; + *(Cptr + 3) =3D 'i'; + *(Cptr + 4) =3D '\0'; + } + + LongFilePathName =3D LongFilePath(PeFileName); + if (LongFilePathName =3D=3D NULL) { + Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for fi= le %s.", FileName); + return EFI_ABORTED; + } + PeFile =3D fopen(LongFilePathName, "rb"); + if (PeFile =3D=3D 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 sect= ion.", FileName); + //return EFI_ABORTED; + } + else { + // + // Get the file size + // + PeFileSize =3D _filelength(fileno(PeFile)); + PeFileBuffer =3D (UINT8 *)malloc(PeFileSize); + if (PeFileBuffer =3D=3D 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 =3D PeFileBuffer; + Status =3D PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s an= d the return status is %x", FileName, (int)Status); + return Status; + } + ImageContext.RelocationsStripped =3D 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 =3D (UINT8 *)malloc((UINTN)ImageContext.ImageSize += ImageContext.SectionAlignment); + if (MemoryImagePointer =3D=3D NULL) { + Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on reba= se of %s", FileName); + return EFI_OUT_OF_RESOURCES; + } + memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + = ImageContext.SectionAlignment); + ImageContext.ImageAddress =3D ((UINTN)MemoryImagePointer + ImageContex= t.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1)); + + Status =3D 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 =3D NewPe32BaseAddress; + Status =3D PeCoffLoaderRelocateImage(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on reba= se of TE image %s", FileName); + free((VOID *)MemoryImagePointer); + return Status; + } + + // + // Copy the relocated image into raw image file. + // + SectionHeader =3D (EFI_IMAGE_SECTION_HEADER *)(TEImageHeader + 1); + for (Index =3D 0; Index < TEImageHeader->NumberOfSections; Index++, Se= ctionHeader++) { + if (!ImageContext.IsTeImage) { + CopyMem( + (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHea= der->StrippedSize + SectionHeader->PointerToRawData, + (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->Virtua= lAddress), + SectionHeader->SizeOfRawData + ); + } + else { + CopyMem( + (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHea= der->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 =3D NULL; + if (PeFileBuffer !=3D NULL) { + free(PeFileBuffer); + PeFileBuffer =3D NULL; + } + + // + // Update Image Base Address + // + TEImageHeader->ImageBase =3D NewPe32BaseAddress; + + // + // Now update file checksum + // + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState =3D FfsFile->State; + FfsFile->IntegrityCheck.Checksum.File =3D 0; + FfsFile->State =3D 0; + FfsFile->IntegrityCheck.Checksum.File =3D CalculateChecksum8( + (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize), + GetFfsFileLength(FfsFile) - FfsHeaderSize + ); + FfsFile->State =3D 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 FileOff= set + +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/COF= F file starting at FileOffset + +--*/ +{ + CHAR8 *Destination8; + CHAR8 *Source8; + UINT32 Length; + + Destination8 =3D Buffer; + Source8 =3D (CHAR8 *)((UINTN)FileHandle + FileOffset); + Length =3D *ReadSize; + while (Length--) { + *(Destination8++) =3D *(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 =3D NULL; + GetFvHeader (&OrigFvHeader, &OrigFvLength); + OrigFvBaseAddress =3D BaseAddress; + for (Index =3D 1;; Index++) { + // + // Find FV section + // + Status =3D GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAG= E, Index, &SubFvSection); + if (EFI_ERROR (Status)) { + break; + } + SubFvImageHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSe= ction.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection)); + + // + // Rebase on Flash + // + SubFvBaseAddress =3D OrigFvBaseAddress + (UINTN) SubFvImageHeader - (U= INTN) FfsFile + XipOffset; + //mFvBaseAddress[mFvBaseAddressNumber ++ ] =3D SubFvBaseAddress; + BaseAddress =3D SubFvBaseAddress; + InitializeFvLib(SubFvImageHeader, (UINT32) SubFvImageHeader->FvLength); + + Status =3D GetNextFile (NULL, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file can't be f= ound"); + continue; + } + while (CurrentFile) { + RebaseFfs (BaseAddress, "", CurrentFile, (UINTN) CurrentFile - (UINT= N) SubFvImageHeader); + Status =3D GetNextFile (CurrentFile, &CurrentFile); + if (EFI_ERROR (Status)) { + break; + } + } + } + + BaseAddress =3D OrigFvBaseAddress; + if (OrigFvHeader !=3D 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 be= ginning + of the PE32 buffer passed in. + +Arguments: + + Pe32 Beginning of the PE32. + EntryPoint Offset from the beginning of the PE32 to the image entry p= oint. + 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // First check whether it is one TE Image. + // + TeHeader =3D (EFI_TE_IMAGE_HEADER *) Pe32; + if (TeHeader->Signature =3D=3D EFI_TE_IMAGE_HEADER_SIGNATURE) { + // + // By TeImage Header to get output + // + *EntryPoint =3D TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE= _HEADER) - TeHeader->StrippedSize; + *BaseOfCode =3D TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) = - TeHeader->StrippedSize; + *MachineType =3D TeHeader->Machine; + } else { + + // + // Then check whether + // First is the DOS header + // + DosHeader =3D (EFI_IMAGE_DOS_HEADER *) Pe32; + + // + // Verify DOS header is expected + // + if (DosHeader->e_magic !=3D EFI_IMAGE_DOS_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS he= ader, 0x%04X.", DosHeader->e_magic); + return EFI_UNSUPPORTED; + } + // + // Immediately following is the NT header. + // + ImgHdr =3D (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHead= er->e_lfanew); + + // + // Verify NT header is expected + // + if (ImgHdr->Pe32.Signature !=3D EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08= X.", (unsigned) ImgHdr->Pe32.Signature); + return EFI_UNSUPPORTED; + } + // + // Get output + // + *EntryPoint =3D ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint; + *BaseOfCode =3D ImgHdr->Pe32.OptionalHeader.BaseOfCode; + *MachineType =3D ImgHdr->Pe32.FileHeader.Machine; + } + + // + // Verify machine type is supported + // + if ((*MachineType !=3D EFI_IMAGE_MACHINE_IA32) && (*MachineType !=3D EFI= _IMAGE_MACHINE_X64) && (*MachineType !=3D EFI_IMAGE_MACHINE_EBC) && + (*MachineType !=3D EFI_IMAGE_MACHINE_ARMT) && (*MachineType !=3D EFI= _IMAGE_MACHINE_AARCH64)) { + Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE3= 2 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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _FMMT_REBASE_H +#define _FMMT_REBASE_H + +#include +#include + +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 --=20 2.18.0.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#42669): https://edk2.groups.io/g/devel/message/42669 Mute This Topic: https://groups.io/mt/32154334/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Wed May 1 07:02:20 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+42670+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+42670+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1561080415; cv=none; d=zoho.com; s=zohoarc; b=FO1Sb1FBcdGzgyTx+u4ajciVpRcITIE0qbijtMc9fDXfs32kI8Uef4YLuAOuWyq1sdLhKx2R8Bvwgk2/de+++zr4zqYp9NtdqVjCIZsDSs21u70ASWc9xiTj85dophk9XGdI83iPKrZZcYcdaF9gahH0eShTOusHjKm8lwXxJSc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1561080415; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To:ARC-Authentication-Results; bh=EQZDf8iXIIQvmFc61qcKxQUKZg/l8CT57DkmkhoRvyM=; b=FOKhjSIRR2GM1UGijdiDFUCNmRrhKqArkIuLy2YQkx5u0OkVCmHnR8DkNjW5S3Lw7oplJCRUG5imNRLh02/lVhe4jAFa6NpkQWg6Kv/YM56ARlJUBkE3djTjjRSHAspecdxYWbrcivu/eqfnNGX9HhhGlAa8N/vy8bjZcocVpLo= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+42670+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1561080415785921.5881109259184; Thu, 20 Jun 2019 18:26:55 -0700 (PDT) Return-Path: X-Received: from mga01.intel.com (mga01.intel.com []) by groups.io with SMTP; Thu, 20 Jun 2019 18:26:54 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 Jun 2019 18:26:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,398,1557212400"; d="scan'208";a="358723167" X-Received: from shenglei-dev.ccr.corp.intel.com ([10.239.158.52]) by fmsmga005.fm.intel.com with ESMTP; 20 Jun 2019 18:26:52 -0700 From: "Zhang, Shenglei" To: devel@edk2.groups.io Cc: Bob Feng , Liming Gao Subject: [edk2-devel] [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib Date: Fri, 21 Jun 2019 09:26:39 +0800 Message-Id: <20190621012643.9352-3-shenglei.zhang@intel.com> In-Reply-To: <20190621012643.9352-1-shenglei.zhang@intel.com> References: <20190621012643.9352-1-shenglei.zhang@intel.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,shenglei.zhang@intel.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1561080415; bh=qAAdOhqa+RlYjH069UbLGvADF45E2jzNUz4rmsUHxO8=; h=Cc:Date:From:Reply-To:Subject:To; b=XyvT3xN2TxSyQn9IgTTjz0WtcbylLjn1suDqcvYJpLy2mUMZzqqFctgnmSwrjrieiTo D9ArAAsz54p/U9n9WyUUIlYp70/O1bXXfaiSMjvttULBUA80RPRdvkuanxs8Y9V8/9Jv+ Ds5nLtkrvymGIc4CsrdIitiEgq26IDmgP68= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" BmfLib is added for FCE tool. https://bugzilla.tianocore.org/show_bug.cgi?id=3D1848 Cc: Bob Feng Cc: Liming Gao Signed-off-by: Shenglei Zhang --- 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/Bf= mLib/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.
+ 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) =3D=3D Bit) : ((TestAttributes & Bit) =3D=3D 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\" > /de= v/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] =3D {0x78, 0xE5, 0x8C, 0x8C, 0x3D,= 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3}; + +CHAR8 mFirmwareFileSystem3Guid[16] =3D {0x7A, 0xC0, 0x73, 0x54, 0xCB,= 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A }; +extern CHAR8* mGuidToolDefinition; +UINT32 PadSizeOfBfv; + +static CHAR8 *mSectionTypeName[] =3D { + 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[] =3D { + 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 =3D=3D NULL) { + return NULL; + } + + memset (Fv, '\0', sizeof (FV_INFORMATION)); + + for (Index =3D 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 =3D TRUE; + Fv->FfsAttuibutes[Index].TotalSectionNum =3D 0; + } + + Fv->PatchData =3D NULL; + Fv->EncapData =3D NULL; + Fv->FvNext =3D NULL; + Fv->FvLevel =3D 0; + Fv->IsBfvFlag =3D FALSE; + Fv->IsInputFvFlag =3D FALSE; + + return Fv; +} + +/** + Generate the unique template filename. +**/ +CHAR8 * +GenTempFile ( + VOID + ) +{ + CHAR8 *TemString; + TemString =3D NULL; +#ifndef __GNUC__ + TemString =3D CloneString (tmpnam (NULL)); +#else + CHAR8 tmp[] =3D "/tmp/fileXXXXXX"; + UINTN Fdtmp; + Fdtmp =3D mkstemp(tmp); + TemString =3D 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] =3D "_FVH"; + FV_INFORMATION *CurrentFv; + FV_INFORMATION *NewFoundFv; + BOOLEAN FirstMatch; + UINT32 FdSize; + UINT16 FvCount; + VOID *FdBuffer; + VOID *FdBufferOri; + UINT32 Count; + + + CurrentFv =3D NULL; + NewFoundFv =3D NULL; + FdBuffer =3D NULL; + FdBufferOri =3D NULL; + FirstMatch =3D TRUE; + Index =3D 0; + FdSize =3D 0; + FvCount =3D 0; + Count =3D 0; + LocalFdData =3D NULL; + + if (InputFile =3D=3D NULL) { + return EFI_ABORTED; + } + + // + // Find each FVs in the FD + // + + fseek(InputFile,0,SEEK_SET); + fseek(InputFile,0,SEEK_END); + + FdSize =3D ftell(InputFile); + + fseek(InputFile,0,SEEK_SET); + // + // Create an FD structure to store useful information. + // + LocalFdData =3D (FIRMWARE_DEVICE *) calloc (sizeof (FIRMWARE_DEVICE)= , sizeof(UINT8)); + if (LocalFdData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + LocalFdData->Fv =3D (FV_INFORMATION *) calloc (sizeof (FV_INFORMATION),= sizeof(UINT8)); + if (LocalFdData->Fv =3D=3D NULL) { + free (LocalFdData); + return EFI_OUT_OF_RESOURCES; + } + LibInitializeFvStruct (LocalFdData->Fv); + + // + // Readout the FD file data to buffer. + // + FdBuffer =3D malloc (FdSize); + + if (FdBuffer =3D=3D NULL) { + free (LocalFdData->Fv); + free (LocalFdData); + return EFI_OUT_OF_RESOURCES; + } + + if (fread (FdBuffer, 1, FdSize, InputFile) !=3D FdSize) { + free (LocalFdData->Fv); + free (LocalFdData); + free (FdBuffer); + return EFI_ABORTED; + } + + FdBufferOri =3D FdBuffer; + + for (Count=3D0; Count < FdSize - 4; Count++) { + // + // Copy 4 bytes of fd data to check the _FVH signature + // + memcpy (SignatureCheck, FdBuffer, 4); + FdBuffer =3D(UINT8 *)FdBuffer + 4; + + if (strncmp(SignatureCheck, Signature, 4) =3D=3D 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 =3D (UINT8 *)FdBuffer - 28; + memcpy (Ffs2Guid, FdBuffer, 16); + + // + // Compare GUID. + // + for (Index =3D 0; Index < 16; Index ++) { + if (Ffs2Guid[Index] !=3D mFirmwareFileSystem2Guid[Index]) { + break; + } + } + if (Index !=3D 16) { + for (Index =3D 0; Index < 16; Index ++) { + if (Ffs2Guid[Index] !=3D mFirmwareFileSystem3Guid[Index]) { + break; + } + } + } + + // + // Point to the original address + // + FdBuffer =3D (UINT8 *)FdBuffer + 28; + + // + // Here we found an FV. + // + if (Index =3D=3D 16) { + if (FirstMatch) { + LocalFdData->Fv->ImageAddress =3D (UINTN)((UINT8 *)FdBuffer - (U= INT8 *)FdBufferOri) - 0x2c; + CurrentFv =3D LocalFdData->Fv; + CurrentFv->FvNext =3D NULL; + // + // Store the FV name by found sequence + // + sprintf(CurrentFv->FvName, "FV%d", FvCount); + + FirstMatch =3D FALSE; + } else { + NewFoundFv =3D (FV_INFORMATION *) malloc (sizeof (FV_INFORMATI= ON)); + if (NULL =3D=3D NewFoundFv) { + free (LocalFdData->Fv); + free (LocalFdData); + free (FdBuffer); + return EFI_OUT_OF_RESOURCES; + } + + LibInitializeFvStruct (NewFoundFv); + + // + // Need to turn back 0x2c bytes + // + NewFoundFv->ImageAddress =3D (UINTN)((UINT8 *)FdBuffer - (UINT= 8 *)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 =3D NULL; + CurrentFv->FvNext =3D NewFoundFv; + + // + // Make the CurrentFv point to next FV. + // + CurrentFv =3D CurrentFv->FvNext; + } + + FvCount ++; + Index =3D 0; + } + + } + + // + // We need to turn back 3 bytes. + // + FdBuffer =3D (UINT8 *)FdBuffer - 3; + } + + LocalFdData->Size =3D FdSize; + + *FdData =3D 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 =3D 0; + Size =3D 0; + + if (InputFile =3D=3D NULL || FvSize =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_B= LOCK_MAP_ENTRY), SEEK_CUR); + do { + fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile); + BytesRead +=3D sizeof (EFI_FV_BLOCK_MAP_ENTRY); + + if (BlockMap.NumBlocks !=3D 0) { + Size +=3D BlockMap.NumBlocks * BlockMap.Length; + } + } while (!(BlockMap.NumBlocks =3D=3D 0 && BlockMap.Length =3D=3D 0)); + + + *FvSize =3D 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 =3D 0; + hdr =3D (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + blk =3D hdr->BlockMap; + + while (blk->Length !=3D 0 || blk->NumBlocks !=3D 0) { + *Size =3D *Size + (blk->Length * blk->NumBlocks); + if (*Size >=3D 0x40000000) { + // + // If size is greater than 1GB, then assume it is corrupted + // + return EFI_VOLUME_CORRUPTED; + } + blk++; + } + + if (*Size =3D=3D 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 s= hould be + passed back in without modifying it's contents to re= trieve + subsequent files. + @param[in] File- Output file pointer + File =3D=3D 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 =3D (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + fhdr =3D NULL; + + if (Fv =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*Key =3D=3D 0) { + if (hdr->ExtHeaderOffset !=3D 0) { + // + // Searching for files starts on an 8 byte aligned boundary after th= e end of the Extended Header if it exists. + // + FwVolExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) hdr= + hdr->ExtHeaderOffset); + *Key =3D (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSiz= e; + *Key =3D (UINTN)ALIGN_POINTER (*Key, 8); + } else { + *Key =3D hdr->HeaderLength; + } + } + + FvbAttributes =3D hdr->Attributes; + + for( + *Key =3D (UINTN)ALIGN_POINTER (*Key, 8); + (*Key + sizeof (*fhdr)) < fvSize; + *Key =3D (UINTN)ALIGN_POINTER (*Key, 8) + ) { + fhdr =3D (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key); + fsize =3D 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 =3D *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 =3D *Key + fsize; + continue; + } else if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DATA_VALID + ) + ) { + *File =3D (UINT8*)hdr + *Key; + *Key =3D *Key + fsize; + return EFI_SUCCESS; + } + + *Key =3D *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 =3D 0; + FfsFileName =3D NULL; + FfsFile =3D NULL; + TempDir =3D NULL; + + TempDir =3D 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 =3D (CHAR8 *) malloc (_MAX_PATH); + if (NULL =3D=3D FfsFileName) { + return EFI_ABORTED; + } + memset (FfsFileName, '\0', _MAX_PATH); + FfsFileSize =3D 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) + st= rlen(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 =3D (UINT8)~(CurrentFile->State); + } + + FfsFile =3D fopen (FfsFileName, "wb+"); + if (FfsFile =3D=3D NULL) { + free(FfsFileName); + return EFI_ABORTED; + } + + if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) !=3D FfsFileSize) { + fclose(FfsFile); + free(FfsFileName); + return EFI_ABORTED; + } + + fclose(FfsFile); + free(FfsFileName); + FfsFileName =3D NULL; + + CurrentFv->FfsNumbers =3D *FfsCount; + + *FfsCount +=3D 1; + + if (ErasePolarity) { + CurrentFile->State =3D (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 =3D NULL; + + FfsFileSize =3D GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile); + FfsDataSize =3D FfsFileSize - GetFfsHeaderLength ((EFI_FFS_FILE_HEADER = *) CurrentFile); + FfsData =3D (EFI_GUID *) ((INT8 *)CurrentFile + GetFfsHeaderLength = ((EFI_FFS_FILE_HEADER *) CurrentFile)); + + if (FfsDataSize =3D=3D 0) { + return TRUE; + } + + LocalEncapData =3D CurrentFv->EncapData; + + do { + if (LocalEncapData->FvExtHeader !=3D NULL) { + if (CompareGuid(FfsData, &LocalEncapData->FvExtHeader->FvName) =3D= =3D 0) { + return TRUE; + } + } + LocalEncapData =3D LocalEncapData->NextNode; + } while (LocalEncapData->NextNode !=3D NULL); + + return FALSE; +} + +BOOLEAN +LibCheckPadFfsNotNull ( + IN EFI_FFS_FILE_HEADER2 *CurrentFile +) +{ + UINT32 FfsFileSize; + UINT32 FfsDataSize; + INT8 *FfsData; + + FfsFileSize =3D GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile); + FfsDataSize =3D FfsFileSize - GetFfsHeaderLength ((EFI_FFS_FILE_HEADER = *) CurrentFile); + FfsData =3D (INT8 *)CurrentFile + GetFfsHeaderLength ((EFI_FFS_FILE= _HEADER *) CurrentFile); + + if (FfsDataSize =3D=3D 0) { + return FALSE; + } + + while (FfsDataSize > 0) { + if (((FfsData[FfsDataSize-1]) & 0xFF) !=3D 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 =3D 0; + MaxSize =3D 0; + + if (PadFfsHeader =3D=3D NULL) { + return MaxSize; + } + + FfsSize =3D GetFfsFileLength ((EFI_FFS_FILE_HEADER *) PadFfsHeader); + HeaderSize =3D GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) PadFfsHeade= r); + + for (Count =3D HeaderSize; Count < FfsSize; Count++) { + if (((((INT8 *)PadFfsHeader)[Count]) & 0xFF) =3D=3D 0xFF) { + Index++; + } else { + if (Index > MaxSize) { + MaxSize =3D Index; + } + Index =3D 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 addition= al 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 =3D 0; + Count1 =3D 0; + Count2 =3D 0; + FfsOffset =3D 0; + DataOffset =3D 0; + FfsFoundFlag =3D FALSE; + LocalPatchData =3D NULL; + + if (CurrentFv =3D=3D NULL || CurrentFile =3D=3D NULL || FvImage =3D=3D N= ULL) { + return EFI_ABORTED; + } + + FfsFileSize =3D GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile); + HeaderSize =3D GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile= ); + + for (Count1=3D0; Count1 < (FvImage->FvLength - FfsFileSize); Count1 ++) { + for (Count2=3D0; Count2 < FfsFileSize; Count2 ++) { + if (((INT8*)FvImage)[Count1 + Count2] !=3D ((INT8 *) CurrentFile)[Co= unt2]){ + break; + } + } + if (Count2 =3D=3D FfsFileSize) { + FfsFoundFlag =3D TRUE; + FfsOffset =3D Count1; + break; + } + } + + if (FfsFoundFlag) { + // + // Find data in FFS file; + // Will skip FFS header; + // + for (Count1 =3D HeaderSize; Count1 < FfsFileSize; Count1++) { + if (((((INT8 *)CurrentFile)[Count1]) & 0xFF) !=3D 0xFF) { + DataOffset =3D FfsOffset + Count1; + break; + } + } + + if (CurrentFv->PatchData =3D=3D NULL) { + // + // First time found data. + // + CurrentFv->PatchData =3D (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATC= H_DATA_PAD_FFS)); + if (CurrentFv->PatchData =3D=3D NULL) { + return EFI_ABORTED; + } + + CurrentFv->PatchData->Offset =3D DataOffset; + CurrentFv->PatchData->Data =3D malloc(FfsFileSize - Count1); + CurrentFv->PatchData->Length =3D FfsFileSize - Count1; + CurrentFv->PatchData->NextNode =3D NULL; + + if (CurrentFv->PatchData->Data =3D=3D NULL) { + return EFI_ABORTED; + } + + memcpy (CurrentFv->PatchData->Data, (INT8 *)CurrentFile + Count1, Ff= sFileSize - Count1); + } else { + LocalPatchData =3D CurrentFv->PatchData; + + while (LocalPatchData->NextNode !=3D NULL) { + LocalPatchData =3D LocalPatchData->NextNode; + } + + LocalPatchData =3D (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATCH_DATA= _PAD_FFS)); + + if (LocalPatchData =3D=3D NULL) { + return EFI_ABORTED; + } + + LocalPatchData->Offset =3D DataOffset; + LocalPatchData->Data =3D malloc(FfsFileSize - Count1); + LocalPatchData->Length =3D FfsFileSize - Count1; + LocalPatchData->NextNode =3D NULL; + + if (LocalPatchData->Data =3D=3D NULL) { + free (LocalPatchData); + return EFI_ABORTED; + } + + memcpy (LocalPatchData->Data, (INT8 *)CurrentFile + Count1, FfsFileS= ize - Count1); + while (CurrentFv->PatchData->NextNode !=3D NULL) { + CurrentFv->PatchData =3D CurrentFv->PatchData->NextNode; + } + CurrentFv->PatchData->NextNode =3D 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 =3D 0; + RetStr =3D NULL; + + RetStr =3D (CHAR8 *) malloc (Count +1); + + if (NULL =3D=3D RetStr) { + return NULL; + } + + memset (RetStr , '\0', Count + 1); + + for (Index=3D0; Index <=3D Count -1; Index ++) { + RetStr[Index] =3D ' '; + } + + return RetStr; + +} + +VOID +Unicode2AsciiString ( + IN CHAR16 *Source, + OUT CHAR8 *Destination + ) + /*++ + + Routine Description: + + Convert a null-terminated unicode string to a null-terminated ascii stri= ng. + + 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 !=3D '\0') { + *(Destination++) =3D (CHAR8) *(Source++); + } + // + // End the ascii with a NULL. + // + *Destination =3D '\0'; +} + + +/** + + Parses EFI Sections, if the view flag turn on, then will collect FFS sec= tion 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 =3D 0; + ToolOutputLength =3D 0; + UINameSize =3D 0; + NumberOfSections =3D 0; + UncompressedLength =3D 0; + CompressedLength =3D 0; + CompressionType =3D 0; + DstSize =3D 0; + ScratchSize =3D 0; + Ptr =3D NULL; + ExtractionTool =3D NULL; + ToolInputFile =3D NULL; + ToolOutputFile =3D NULL; + SystemCommand =3D NULL; + ToolOutputBuffer =3D NULL; + UIName =3D NULL; + LocalEncapData =3D NULL; + BlankChar =3D NULL; + UncompressedBuffer =3D NULL; + CompressedBuffer =3D NULL; + ScratchBuffer =3D NULL; + TempDir =3D NULL; + ToolInputFileFullName =3D NULL; + ToolOutputFileFullName =3D NULL; + ToolInputFileName =3D NULL; + ToolOutputFileName =3D NULL; + HasDepexSection =3D FALSE; + IsFfsGenerated =3D FfsGeneratedFlag; + EncapDataNeedUpdata =3D TRUE; + LargeHeaderOffset =3D 0; + + + while (ParsedLength < BufferLength) { + Ptr =3D SectionBuffer + ParsedLength; + + SectionLength =3D FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)= Ptr)->Size); + Type =3D ((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 se= ction + // header worth of 0xFF bytes. + // + if (SectionLength =3D=3D 0xffffff && Type =3D=3D 0xff) { + ParsedLength +=3D 4; + continue; + } + // + //If Size is 0xFFFFFF then ExtendedSize contains the size of the section. + // + if (SectionLength =3D=3D 0xffffff) { + SectionLength =3D ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSi= ze; + LargeHeaderOffset =3D sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EF= I_COMMON_SECTION_HEADER); + } + + switch (Type) { + + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: + EncapDataNeedUpdata =3D TRUE; + + Level ++; + NumberOfSections ++; + + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf =3D FALSE; + + // + // Put in encapsulate data information. + // + LocalEncapData =3D CurrentFv->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D Level) { + EncapDataNeedUpdata =3D FALSE; + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + if (EncapDataNeedUpdata) { + // + // Put in this is an FFS with FV section + // + LocalEncapData =3D CurrentFv->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + } + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (E= NCAP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D BFM_ENCAP_TREE_FV_SECTION; + + // + // We don't need additional data for encapsulate this FFS but type. + // + LocalEncapData->Data =3D NULL; + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->NextNode =3D NULL; + } + + Status =3D LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION= *)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, FfsCount, ViewFla= g, TRUE); + if (EFI_ERROR (Status)) { + return EFI_SECTION_ERROR; + } + break; + + case EFI_SECTION_COMPRESSION: + Level ++; + NumberOfSections ++; + + EncapDataNeedUpdata =3D TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData =3D CurrentFv->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D Level) { + EncapDataNeedUpdata =3D FALSE; + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + if (EncapDataNeedUpdata) { + // + // Put in this is an FFS with FV section + // + LocalEncapData =3D CurrentFv->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + } + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (E= NCAP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D BFM_ENCAP_TREE_COMPRESS_SECTION; + + // + // Store the compress type + // + LocalEncapData->Data =3D malloc (sizeof (UINT8)); + + if (LocalEncapData->Data =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *(UINT8 *)LocalEncapData->Data =3D ((EFI_COMPRESSION_SECTION *= ) (Ptr + LargeHeaderOffset))->CompressionType; + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->NextNode =3D NULL; + } + + // + // Process compressed section + // + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf =3D FALSE; + + UncompressedBuffer =3D NULL; + CompressedLength =3D SectionLength - sizeof (EFI_COMPRESSION_SECT= ION) - LargeHeaderOffset; + UncompressedLength =3D ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHea= derOffset))->UncompressedLength; + CompressionType =3D ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHea= derOffset))->CompressionType; + + if (CompressionType =3D=3D EFI_NOT_COMPRESSED) { + + if (CompressedLength !=3D UncompressedLength) { + printf ("Error. File is not compressed, but the compressed lengt= h does not match the uncompressed length.\n"); + return EFI_SECTION_ERROR; + } + + UncompressedBuffer =3D Ptr + sizeof (EFI_COMPRESSION_SECTION) + La= rgeHeaderOffset; + } else if (CompressionType =3D=3D EFI_STANDARD_COMPRESSION) { + GetInfoFunction =3D EfiGetInfo; + DecompressFunction =3D EfiDecompress; + + CompressedBuffer =3D Ptr + sizeof (EFI_COMPRESSION_SECTION) + Lar= geHeaderOffset; + + Status =3D GetInfoFunction (CompressedBuffer, Compresse= dLength, &DstSize, &ScratchSize); + if (EFI_ERROR (Status)) { + return EFI_SECTION_ERROR; + } + + if (DstSize !=3D UncompressedLength) { + return EFI_SECTION_ERROR; + } + + ScratchBuffer =3D malloc (ScratchSize); + if (ScratchBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + UncompressedBuffer =3D malloc (UncompressedLength); + + if (UncompressedBuffer =3D=3D NULL) { + free (ScratchBuffer); + return EFI_OUT_OF_RESOURCES; + } + // + // Decompress the section. + // + Status =3D 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 =3D LibParseSection ( UncompressedBuffer, + UncompressedLength, + CurrentFv, + FvName, + CurrentFile, + Level, + FfsCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated); + + if (CompressionType =3D=3D 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 =3D TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData =3D CurrentFv->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D Level) { + EncapDataNeedUpdata =3D FALSE; + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + if (EncapDataNeedUpdata) { + + // + // Put in this is an FFS with FV section + // + LocalEncapData =3D CurrentFv->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + } + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (E= NCAP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D BFM_ENCAP_TREE_GUIDED_SECTION; + + // + // We don't need additional data for encapsulate this FFS but type. + // + + LocalEncapData->Data =3D (EFI_GUID *) malloc (sizeof (EFI_GUID= )); + + if (LocalEncapData->Data =3D=3D NULL) { + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, &((EFI_GUID_DEFINED_SECTION *) (Ptr + La= rgeHeaderOffset))->SectionDefinitionGuid, sizeof (EFI_GUID)); + + LocalEncapData->FvExtHeader =3D NULL; + LocalEncapData->NextNode =3D NULL; + } + + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf =3D FALSE; + + ExtractionTool =3D + LookupGuidedSectionToolPath ( + mParsedGuidedSectionTools, + &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->Secti= onDefinitionGuid + ); + + if ((((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->Attri= butes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) =3D=3D 0) { + // + // Not require process, directly gets data. + // + Status =3D LibParseSection ( + Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->= DataOffset, + SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeader= Offset))->DataOffset, + CurrentFv, + FvName, + CurrentFile, + Level, + FfsCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated + ); + if (ExtractionTool !=3D NULL) { + free (ExtractionTool); + ExtractionTool =3D NULL; + } + if (EFI_ERROR (Status)) { + return EFI_SECTION_ERROR; + } + } else if (ExtractionTool !=3D NULL) { + + TempDir =3D 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 =3D GenTempFile (); + ToolOutputFile =3D GenTempFile (); + ToolInputFileName =3D strrchr(ToolInputFile, OS_SEP); + ToolOutputFileName =3D strrchr(ToolOutputFile, OS_SEP); + + ToolInputFileFullName =3D malloc (strlen("%s%s") + strlen(TempDi= r) + strlen(ToolInputFileName) + 1); + if (ToolInputFileFullName =3D=3D NULL) { + free (ExtractionTool); + free (ToolInputFile); + free (ToolOutputFile); + return EFI_OUT_OF_RESOURCES; + } + ToolOutputFileFullName =3D malloc (strlen("%s%s") + strlen(TempDi= r) + strlen(ToolOutputFileName) + 1); + if (ToolOutputFileFullName =3D=3D 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, ToolOutputFileNa= me); + + // + // Construction 'system' command string + // + SystemCommand =3D malloc ( + strlen (DECODE_STR) + + strlen (ExtractionTool) + + strlen (ToolInputFileFullName) + + strlen (ToolOutputFileFullName) + + 1 + ); + if (SystemCommand =3D=3D NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ToolInputFileFullName); + free (ToolOutputFileFullName); + free (ExtractionTool); + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + DECODE_STR, + ExtractionTool, + ToolOutputFileFullName, + ToolInputFileFullName + ); + + Status =3D PutFileImage ( + ToolInputFileFullName, + (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOff= set))->DataOffset, + SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOf= fset))->DataOffset + ); + + if (HasDepexSection) { + HasDepexSection =3D FALSE; + } + + if (EFI_ERROR (Status)) { + free(SystemCommand); + free (ToolOutputFileFullName); + free (ToolOutputFile); + remove (ToolInputFileFullName); + free (ToolInputFile); + free (ToolInputFileFullName); + return EFI_SECTION_ERROR; + } + + if (system (SystemCommand) !=3D EFI_SUCCESS) { + SystemCommand =3D malloc ( + strlen (DECODE_STR_ERR) + + strlen (ExtractionTool) + + strlen (ToolInputFileFullName) + + strlen (ToolOutputFileFullName) + + 1 + ); + if (SystemCommand =3D=3D 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 =3D NULL; + LibRmDir (TempDir); + free(SystemCommand); + remove (ToolInputFileFullName); + free (ToolInputFile); + free (ToolInputFileFullName); + free (ToolOutputFileFullName); + free (ToolOutputFile); + return EFI_ABORTED; + } + free (ExtractionTool); + ExtractionTool =3D NULL; + free (SystemCommand); + remove (ToolInputFileFullName); + free (ToolInputFile); + free (ToolInputFileFullName); + ToolInputFile =3D NULL; + ToolInputFileFullName =3D NULL; + + + Status =3D GetFileImage ( + ToolOutputFileFullName, + (CHAR8 **)&ToolOutputBuffer, + &ToolOutputLength + ); + remove (ToolOutputFileFullName); + free (ToolOutputFile); + free (ToolOutputFileFullName); + ToolOutputFile =3D NULL; + ToolOutputFileFullName =3D NULL; + + if (EFI_ERROR (Status)) { + return EFI_SECTION_ERROR; + } + + Status =3D 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 !=3D NULL) { + free (ExtractionTool); + ExtractionTool =3D 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", mGuidT= oolDefinition); + 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 =3D Level; + if (!ViewFlag) { + if (!IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + IsFfsGenerated =3D TRUE; + } + } + + break; + case EFI_SECTION_PE32: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + IsFfsGenerated =3D TRUE; + } + } + + break; + case EFI_SECTION_PIC: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + IsFfsGenerated =3D TRUE; + } + } + + break; + case EFI_SECTION_TE: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + IsFfsGenerated =3D TRUE; + } + } + break; + + case EFI_SECTION_COMPATIBILITY16: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + + if (!ViewFlag) { + if (!IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + IsFfsGenerated =3D TRUE; + } + } + break; + + case EFI_SECTION_FREEFORM_SUBTYPE_GUID: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + if (!IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, E= rasePolarity); + IsFfsGenerated =3D TRUE; + } + } + break; + + case EFI_SECTION_VERSION: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + break; + case EFI_SECTION_PEI_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + HasDepexSection =3D TRUE; + break; + case EFI_SECTION_DXE_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + HasDepexSection =3D TRUE; + break; + case EFI_SECTION_SMM_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + HasDepexSection =3D TRUE; + break; + + case EFI_SECTION_USER_INTERFACE: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + + UiSectionLength =3D FvBufExpand3ByteSize (((EFI_USER_INTERFACE_SECTI= ON *) Ptr)->CommonHeader.Size); + if (UiSectionLength =3D=3D 0xffffff) { + UiSectionLength =3D ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonH= eader.ExtendedSize; + UINameSize =3D UiSectionLength - sizeof(EFI_COMMON_SECTION_HEAD= ER2); + } else { + UINameSize =3D UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER); + } + + UIName =3D (CHAR16 *) malloc (UINameSize + 2); + if (UIName !=3D NULL) { + memset (UIName, '\0', UINameSize + 2); + if (UiSectionLength >=3D 0xffffff) { + memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameSt= ring, UINameSize); + } else { + memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameStr= ing, UINameSize); + } + } else { + return EFI_ABORTED; + } + + BlankChar =3D LibConstructBlankChar( CurrentFv->FvLevel * 2); + if (BlankChar =3D=3D NULL) { + free (UIName); + return EFI_ABORTED; + } + + if (ViewFlag) { + UIFileName =3D malloc (UINameSize + 2); + if (UIFileName =3D=3D 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 =3D NULL; + + // + // If Ffs file has been generated, then the FfsCount should decrease= 1. + // + if (IsFfsGenerated) { + memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UIN= ameSize); + } else { + memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UIName= Size); + } + HasDepexSection =3D FALSE; + free(UIName); + UINameSize =3D 0; + + break; + default: + break; + } + + ParsedLength +=3D SectionLength; + // + // We make then next section begin on a 4-byte boundary + // + ParsedLength =3D 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 =3D EFI_SUCCESS; + + LocalEncapData =3D NULL; + EncapDataNeedUpdateFlag =3D TRUE; + + FfsFileHeaderSize =3D GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) Curre= ntFile); + FileLength =3D GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentF= ile); + + // + // 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) =3D=3D 0) { + return EFI_SUCCESS; + } + + // + // Print file information. + // + FileState =3D GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)Curren= tFile); + + if (FileState =3D=3D EFI_FILE_DATA_VALID) { + // + // Calculate header checksum + // + Checksum =3D CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize); + Checksum =3D (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum= .File); + Checksum =3D (UINT8) (Checksum - CurrentFile->State); + if (Checksum !=3D 0) { + return EFI_ABORTED; + } + + if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Calculate file checksum + // + Checksum =3D CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFile= HeaderSize), FileLength - FfsFileHeaderSize); + Checksum =3D Checksum + CurrentFile->IntegrityCheck.Checksum.File; + if (Checksum !=3D 0) { + return EFI_ABORTED; + } + } else { + if (CurrentFile->IntegrityCheck.Checksum.File !=3D FFS_FIXED_CHECKSU= M) { + return EFI_ABORTED; + } + } + } else { + return EFI_ABORTED; + } + + Level +=3D 1; + + if (CurrentFile->Type !=3D EFI_FV_FILETYPE_ALL) { + + // + // Put in encapsulate data information. + // + LocalEncapData =3D CurrentFv->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D Level) { + EncapDataNeedUpdateFlag =3D FALSE; + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + if (EncapDataNeedUpdateFlag) { + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (ENC= AP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + printf ("Out of resource, memory allocation failed. \n"); + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D BFM_ENCAP_TREE_FFS; + LocalEncapData->FvExtHeader =3D NULL; + + // + // Store the header of FFS file. + // + LocalEncapData->Data =3D malloc (FfsFileHeaderSize); + if (LocalEncapData->Data =3D=3D NULL) { + printf ("Out of resource, memory allocation failed. \n"); + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize); + + LocalEncapData->NextNode =3D NULL; + } + + if ( CurrentFile->Type =3D=3D EFI_FV_FILETYPE_FREEFORM ){ + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, Era= sePolarity); + } + }else if ( CurrentFile->Type =3D=3D EFI_FV_FILETYPE_RAW){ + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + if (!ViewFlag){ + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, Era= sePolarity); + } + } else if ( CurrentFile->Type =3D=3D EFI_FV_FILETYPE_SECURITY_CORE){ + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + // + // If an FV contain SECCORE, this FV will be considered as BFV. + // + CurrentFv->IsBfvFlag =3D TRUE; + if (!ViewFlag){ + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, Era= sePolarity); + } + } else if( CurrentFile->Type =3D=3D EFI_FV_FILETYPE_FFS_PAD){ + // + // First check whether the FFS file contain FvExtended FvNameGuid in= formation. + // + if (!LibCheckPadFfsContainFvNameGuid (CurrentFv, CurrentFile)) { + // + // Then check whether the PAD file have no additional data or not. + // + if (LibCheckPadFfsNotNull (CurrentFile)) { + CurrentFv->FfsAttuibutes[*FfsCount].Level =3D Level; + // + // Get the size of PAD in BFV + // + PadSizeOfBfv =3D GetBfvMaxFreeSpace (CurrentFile); + if (!ViewFlag){ + // + //LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCoun= t, ErasePolarity); + // + Status =3D LibFindResetVectorAndFitTableData (FvImage, Current= File, 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 =3D 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 =3D 0; + Key =3D 0; + LocalEncapData =3D NULL; + CurrentFile =3D NULL; + + Level +=3D 1; + CurrentFv->FvLevel +=3D 1; + + Status =3D FvBufGetSize (Fv, &FvSize); + + ErasePolarity =3D (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_F= VB2_ERASE_POLARITY) ? TRUE : FALSE; + + if (!IsChildFv) { + // + // Write FV header information into CurrentFv struct. + // + CurrentFv->FvHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof = (EFI_FIRMWARE_VOLUME_HEADER)); + + if (CurrentFv->FvHeader =3D=3D NULL) { + return EFI_ABORTED; + } + + // + // Get the FV Header information + // + memcpy (CurrentFv->FvHeader, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + CurrentFv->FvExtHeader =3D NULL; + + // + // Exist Extend FV header. + // + if (CurrentFv->FvHeader->ExtHeaderOffset !=3D 0){ + CurrentFv->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc= (sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER)); + + if (CurrentFv->FvExtHeader =3D=3D 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->FvHe= ader->ExtHeaderOffset), sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER)); + if (mFvGuidIsSet) { + if (CompareGuid (&CurrentFv->FvExtHeader->FvName, &mFvNameGuid) = =3D=3D 0) { + CurrentFv->IsInputFvFlag =3D TRUE; + } + } + + } + + } + + // + // Put encapsulate information into structure. + // + if (CurrentFv->EncapData =3D=3D NULL && !IsChildFv) { + // + // First time in, the root FV + // + CurrentFv->EncapData =3D (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INF= O_DATA)); + + if (CurrentFv->EncapData =3D=3D NULL) { + return EFI_ABORTED; + } + CurrentFv->EncapData->FvExtHeader =3D NULL; + CurrentFv->EncapData->Level =3D Level; + CurrentFv->EncapData->Type =3D BFM_ENCAP_TREE_FV; + CurrentFv->EncapData->Data =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc = (sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + + if (CurrentFv->EncapData->Data =3D=3D NULL) { + return EFI_ABORTED; + } + + memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HE= ADER)); + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtH= eaderOffset !=3D 0) { + ExtHdrPtr =3D (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(C= urrentFv->EncapData->Data))->ExtHeaderOffset); + CurrentFv->EncapData->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADE= R *) malloc (ExtHdrPtr->ExtHeaderSize); + + if (CurrentFv->EncapData->FvExtHeader =3D=3D 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, &mFvN= ameGuid) =3D=3D 0) { + CurrentFv->IsInputFvFlag =3D TRUE; + } + } + + } + + CurrentFv->EncapData->NextNode =3D NULL; + + } else if (CurrentFv->EncapData =3D=3D NULL) { + return EFI_ABORTED; + } else if (IsChildFv) { + + LocalEncapData =3D CurrentFv->EncapData; + + while (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + } + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode =3D (ENCAP_INFO_DATA *) malloc (sizeof (ENC= AP_INFO_DATA)); + + if (LocalEncapData->NextNode =3D=3D NULL) { + return EFI_ABORTED; + } + + LocalEncapData =3D LocalEncapData->NextNode; + + LocalEncapData->Level =3D Level; + LocalEncapData->Type =3D BFM_ENCAP_TREE_FV; + LocalEncapData->Data =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc (siz= eof (EFI_FIRMWARE_VOLUME_HEADER)); + LocalEncapData->FvExtHeader =3D NULL; + + if (LocalEncapData->Data =3D=3D NULL) { + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER= )); + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeade= rOffset !=3D 0) { + ExtHdrPtr =3D (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)= (LocalEncapData->Data))->ExtHeaderOffset); + LocalEncapData->FvExtHeader =3D (EFI_FIRMWARE_VOLUME_EXT_HEADER *)= malloc(ExtHdrPtr->ExtHeaderSize); + + if (LocalEncapData->FvExtHeader =3D=3D 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_FIR= MWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr-= >ExtHeaderSize); + } + + LocalEncapData->NextNode =3D NULL; + + } + + + // + // Get the first file + // + Status =3D FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); + if (Status =3D=3D EFI_NOT_FOUND) { + CurrentFile =3D NULL; + } else if (EFI_ERROR (Status)) { + printf ("Failed to find the first file from Fv. \n"); + return Status; + } + + while (CurrentFile !=3D NULL) { + + // + // Increment the number of files counter + // + NumberOfFiles++; + + // + // Store FFS file Header information + // + CurrentFv->FfsHeader[*FfsCount].Attributes =3D CurrentFile->Attr= ibutes; + CurrentFv->FfsHeader[*FfsCount].IntegrityCheck =3D CurrentFile->Inte= grityCheck; + CurrentFv->FfsHeader[*FfsCount].Name =3D CurrentFile->Name; + CurrentFv->FfsHeader[*FfsCount].Size[0] =3D CurrentFile->Size= [0]; + CurrentFv->FfsHeader[*FfsCount].Size[1] =3D CurrentFile->Size= [1]; + CurrentFv->FfsHeader[*FfsCount].Size[2] =3D CurrentFile->Size= [2]; + CurrentFv->FfsHeader[*FfsCount].State =3D CurrentFile->Stat= e; + CurrentFv->FfsHeader[*FfsCount].Type =3D CurrentFile->Type; + CurrentFv->FfsHeader[*FfsCount].ExtendedSize =3D CurrentFile->Exte= ndedSize; + + // + // Display info about this file + // + Status =3D LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, = FvName, Level, FfsCount, ViewFlag); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the next file + // + Status =3D FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); + if (Status =3D=3D EFI_NOT_FOUND) { + CurrentFile =3D 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 =3D NULL; + + TempDir =3D getcwd(NULL, _MAX_PATH); + + if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _M= AX_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] =3D 0; + strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1); + + + ExtFile =3D fopen(OutputExtFile, "wb+"); + if (ExtFile =3D=3D NULL) { + return EFI_ABORTED; + } + + if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) !=3D ExtPtr->ExtHe= aderSize) { + fclose(ExtFile); + return EFI_ABORTED; + } + + fclose(ExtFile); + + strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME =3D "); + 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 (Li= ne) - 1); + strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1); + Len =3D strlen(Line); + if (fwrite(Line, 1, Len, InfFile) !=3D 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 =3D ActualSize; + while ((OccupiedSize & (Alignment - 1)) !=3D 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 !=3D '\0') { + *(UniString++) =3D (CHAR16) *(String++); + } + // + // End the UniString with a NULL. + // + *UniString =3D '\0'; +} + + +EFI_STATUS +LibCreateGuidedSectionOriginalData( + IN CHAR8* FileIn, + IN CHAR8* ToolName, + IN CHAR8* FileOut +) +{ + CHAR8* SystemCommand; + + SystemCommand =3D NULL; + + if (FileIn =3D=3D NULL || + ToolName =3D=3D NULL || + FileOut =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + SystemCommand =3D malloc ( + strlen (ENCODE_STR) + + strlen (FileIn) + + strlen (ToolName) + + strlen (FileOut) + + 1 + ); + + if (NULL =3D=3D SystemCommand) { + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + ENCODE_STR, + ToolName, + FileIn, + FileOut + ); + + if (system (SystemCommand) !=3D EFI_SUCCESS) { + SystemCommand =3D malloc ( + strlen (ENCODE_STR_ERR) + + strlen (FileIn) + + strlen (ToolName) + + strlen (FileOut) + + 1 + ); + if (NULL =3D=3D 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 conver= ted 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 informat= ion. + + @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 =3D NULL; + + LocalStr =3D (CHAR8 *) malloc (1024 * 4); + + if (LocalStr =3D=3D NULL) { + printf ("Out of resource, memory allocation failed. \n"); + return EFI_OUT_OF_RESOURCES; + } + + memset (LocalStr, '\0', 1024 * 4); + + if (Attr =3D=3D 0 || InfFile =3D=3D 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 =3D TRUE \n", sizeof ("EFI_R= EAD_DISABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_ENABLED_CAP) { + strncat (LocalStr, "EFI_READ_ENABLED_CAP =3D TRUE \n", sizeof ("EFI_RE= AD_ENABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_STATUS) { + strncat (LocalStr, "EFI_READ_STATUS =3D TRUE \n", sizeof ("EFI_READ_ST= ATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) { + strncat (LocalStr, "EFI_WRITE_DISABLED_CAP =3D TRUE \n", sizeof ("EFI_= WRITE_DISABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) { + strncat (LocalStr, "EFI_WRITE_ENABLED_CAP =3D TRUE \n", sizeof ("EFI_W= RITE_ENABLED_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_STATUS) { + strncat (LocalStr, "EFI_WRITE_STATUS =3D TRUE \n", sizeof ("EFI_WRITE_= STATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_CAP) { + strncat (LocalStr, "EFI_LOCK_CAP =3D TRUE \n", sizeof ("EFI_LOCK_CAP = =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_STATUS) { + strncat (LocalStr, "EFI_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_LOCK_ST= ATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_STICKY_WRITE) { + strncat (LocalStr, "EFI_STICKY_WRITE =3D TRUE \n", sizeof ("EFI_STICKY= _WRITE =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_MEMORY_MAPPED) { + strncat (LocalStr, "EFI_MEMORY_MAPPED =3D TRUE \n", sizeof ("EFI_MEMOR= Y_MAPPED =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_ERASE_POLARITY) { + strncat (LocalStr, "EFI_ERASE_POLARITY =3D 1 \n", sizeof ("EFI_ERASE_P= OLARITY =3D 1 \n")); + } + + if (Attr & EFI_FVB2_READ_LOCK_CAP) { + strncat (LocalStr, "EFI_READ_LOCK_CAP =3D TRUE \n", sizeof ("EFI_READ_= LOCK_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_LOCK_STATUS) { + strncat (LocalStr, "EFI_READ_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_RE= AD_LOCK_STATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_LOCK_CAP) { + strncat (LocalStr, "EFI_WRITE_LOCK_CAP =3D TRUE \n", sizeof ("EFI_WRIT= E_LOCK_CAP =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) { + strncat (LocalStr, "EFI_WRITE_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_W= RITE_LOCK_STATUS =3D TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_STATUS) { + strncat (LocalStr, "EFI_READ_LOCK_STATUS =3D TRUE \n", sizeof ("EFI_RE= AD_LOCK_STATUS =3D TRUE \n")); + } + + // + // Alignment + // + if (Attr & EFI_FVB2_ALIGNMENT_1) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_1 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_2 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_4 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 =3D TRUE \n", sizeof ("EFI_FV= B2_ALIGNMENT_8 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_16 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_32 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_64 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_128 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_256 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_512 =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_1K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_2K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_4K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_8K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_16K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_32K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_64K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_128K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_256K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_512K =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_1M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_2M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_4M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_8M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_16M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_32M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M =3D TRUE \n", sizeof ("EFI_= FVB2_ALIGNMENT_64M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_128M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_256M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M =3D TRUE \n", sizeof ("EFI= _FVB2_ALIGNMENT_512M =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1G) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_1G =3D TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2G) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G =3D TRUE \n", sizeof ("EFI_F= VB2_ALIGNMENT_2G =3D TRUE \n")); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) !=3D (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 informat= ion. + + @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 =3D NULL; + BlockSize =3D NULL; + NumOfBlocks =3D NULL; + + if (BlockMap =3D=3D NULL || InfFile =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // This section will not over 1024 bytes and each line will never over 1= 28 bytes. + // + LocalStr =3D (CHAR8 *) malloc (1024); + BlockSize =3D (CHAR8 *) malloc (128); + NumOfBlocks =3D (CHAR8 *) malloc (128); + + if (LocalStr =3D=3D NULL || + BlockSize =3D=3D NULL || + NumOfBlocks =3D=3D NULL) { + if (LocalStr !=3D NULL) { + free (LocalStr); + } + if (BlockSize !=3D NULL) { + free (BlockSize); + } + if (NumOfBlocks !=3D 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 =3D 0x%x \n", BlockMap->Length); + strncat (LocalStr, BlockSize, strlen(BlockSize)); + + if (IsRootFv) { + sprintf (NumOfBlocks, "EFI_NUM_BLOCKS =3D 0x%x \n", BlockMap->NumBlocks= ); + strncat (LocalStr, NumOfBlocks, strlen(NumOfBlocks)); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) !=3D (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 informat= ion + @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 =3D NULL; + + if (FfsName =3D=3D NULL || InfFile =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (strlen(FfsName) =3D=3D 0) { + return EFI_SUCCESS; + } + + LocalStr =3D (CHAR8 *) malloc (_MAX_PATH); + + if (LocalStr =3D=3D 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 =3D %s \n", FfsName); + } else { + sprintf (LocalStr, "EFI_FILE_NAME =3D %s \n", FfsName); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) !=3D (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 =3D NULL; + + // + // Call GenSec tool to generate FFS section. + // + + // + // -s SectionType. + // + if (Type !=3D 0) { + switch (Type) { + // + // Process compression section + // + case EFI_SECTION_COMPRESSION: + SystemCommand =3D malloc ( + strlen (GENSEC_COMPRESSION) + + strlen (mSectionTypeName[Type]) + + strlen (CompressType) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENSEC_COMPRESSION, + mSectionTypeName[Type], + CompressType, + InputFilePath, + OutputFilePath + ); + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + // + // Process GUID defined section + // + case EFI_SECTION_GUID_DEFINED: + SystemCommand =3D malloc ( + strlen (GENSEC_GUID) + + strlen (mSectionTypeName[Type]) + + strlen (GuidToolGuid) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENSEC_GUID, + mSectionTypeName[Type], + GuidToolGuid, + InputFilePath, + OutputFilePath + ); + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: + SystemCommand =3D malloc ( + strlen (GENSEC_STR) + + strlen (mSectionTypeName[Type]) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENSEC_STR, + mSectionTypeName[Type], + InputFilePath, + OutputFilePath + ); + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + case EFI_SECTION_RAW: + SystemCommand =3D malloc ( + strlen (GENSEC_STR) + + strlen (mSectionTypeName[Type]) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENSEC_STR, + mSectionTypeName[Type], + InputFilePath, + OutputFilePath + ); + if (system (SystemCommand) !=3D 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 =3D malloc ( + strlen (GENSEC_ALIGN) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENSEC_ALIGN, + InputFilePath, + OutputFilePath + ); + if (system (SystemCommand) !=3D 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 fil= e. This option is required. + @param[in] OutputFilePath The created PI firmware file name. This opt= ion is required. + @param[in] BlockSize BlockSize is one HEX or DEC format value re= quired 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 =3D "8c8ce578-8a3d-4f1c-9935-896185c32dd3= "; + + SystemCommand =3D NULL; + + if (OutputFilePath =3D=3D NULL || + InfFilePath =3D=3D NULL ) { + return EFI_INVALID_PARAMETER; + } + + if (InfFilePath !=3D NULL) { + if (FvGuidName =3D=3D NULL) { + SystemCommand =3D malloc ( + strlen (GENFV_STR) + + strlen (InfFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + + sprintf ( + SystemCommand, + GENFV_STR, + InfFilePath, // -i + OutputFilePath // -o + ); + + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + } else { + // + // Have FvGuidName in it. + // + SystemCommand =3D malloc ( + strlen (GENFV_FVGUID) + + strlen (InfFilePath) + + strlen (OutputFilePath) + + strlen (FvGuidName) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + + sprintf ( + SystemCommand, + GENFV_FVGUID, + InfFilePath, // -i + OutputFilePath, // -o + FvGuidName // FvNameGuid + ); + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + } + } + + if (InputFFSs !=3D NULL) { + SystemCommand =3D malloc ( + strlen (GENFV_FFS) + + strlen (InputFFSs) + + strlen (FfsGuid) + + strlen (OutputFilePath) + + 100 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + + sprintf ( + SystemCommand, + GENFV_FFS, + InputFFSs, // -f + FfsGuid, // -g + OutputFilePath // -o + ); + if (system (SystemCommand) !=3D 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 =3D NULL; + + if (Guid =3D=3D NULL) { + printf ("The guid is NULL while convert guid to string! \n"); + return NULL; + } + + Buffer =3D (CHAR8 *) malloc (36 + 1); + + if (Buffer =3D=3D 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_FILET= YPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE, + EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APP= LICATION, 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 fil= e. This option is required. + @param[in] OutputFilePath The created PI firmware file name. This opt= ion 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 i= ndicate that the file may not be moved from its present location. + @param[in] SectionAlign FileAlign specifies FFS file alignment, whi= ch 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 =3D NULL; + GuidStr =3D NULL; + + GuidStr =3D LibBfmGuidToStr(&FileGuid); + + if (NULL =3D=3D GuidStr) { + return EFI_OUT_OF_RESOURCES; + } + + if (Type =3D=3D EFI_FV_FILETYPE_RAW) { + SystemCommand =3D malloc ( + strlen (GENFFS_STR) + + strlen (mFfsFileType[Type]) + + strlen (InputFilePath) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + free (GuidStr); + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENFFS_STR, + mFfsFileType[Type], // -t + InputFilePath, // -i + GuidStr, // -g + OutputFilePath // -o + ); + + if (system (SystemCommand) !=3D 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 =3D malloc ( + strlen (GENFFS_FIX) + + strlen (mFfsFileType[Type]) + + strlen (InputFilePath) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + free (GuidStr); + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENFFS_FIX, + mFfsFileType[Type], // -t + InputFilePath, // -i + GuidStr, // -g + OutputFilePath // -o + ); + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + free (GuidStr); + return EFI_ABORTED; + } + free(SystemCommand); + } else { + SystemCommand =3D malloc ( + strlen (GENFFS_STR) + + strlen (mFfsFileType[Type]) + + strlen (InputFilePath) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + free (GuidStr); + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENFFS_STR, + mFfsFileType[Type], // -t + InputFilePath, // -i + GuidStr, // -g + OutputFilePath // -o + ); + if (system (SystemCommand) !=3D 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 =3D NULL; + + + if (OldFd =3D=3D NULL || + NewFd =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Create a copy the new file. + // + + SystemCommand =3D malloc ( + strlen (COPY_STR) + + strlen (OldFd) + + strlen (NewFd) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + + sprintf ( + SystemCommand, + COPY_STR, + OldFd, + NewFd + ); + + if (system (SystemCommand) !=3D EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + return EFI_SUCCESS; +} + + +/** + This function will assemble the filename, directory and extend and retur= n the combined string. + Like FileName =3D file1, Dir =3D c:\temp extend =3D txt, the output stri= ng 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 =3D NULL; + + if (FileName =3D=3D NULL) { + return NULL; + } + + if (Dir =3D=3D NULL || Extend =3D=3D NULL) { + return FileName; + } + + RetStr =3D (CHAR8 *) malloc (strlen (FileName) + + strlen (Dir) + + strlen (Extend) + + strlen ("%s%s.%s") + + 1); + if (NULL =3D=3D 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 =3D NULL; + + + if (DirName =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (access (DirName, 0) =3D=3D -1){ + return EFI_SUCCESS; + } + + // + // Delete a directory and files in it + // + SystemCommand =3D malloc ( + strlen (RMDIR_STR) + + strlen (DirName) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + + sprintf ( + SystemCommand, + RMDIR_STR, + DirName + ); + + if (system (SystemCommand) !=3D 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 =3D NULL; + + + if (FileName =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + + // + // Delete a file. + // + SystemCommand =3D malloc ( + strlen (DEL_STR) + + strlen (FileName) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + DEL_STR, + FileName + ); + + if (system (SystemCommand) !=3D 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 =3D NULL; + TempFv =3D NULL; + EncapData1 =3D NULL; + EncapData2 =3D NULL; + + if (Fd =3D=3D NULL) { + return; + } + + CurrentFv =3D Fd->Fv; + + do { + TempFv =3D CurrentFv; + CurrentFv =3D CurrentFv->FvNext; + + if (TempFv->FvHeader !=3D NULL) { + free (TempFv->FvHeader); + } + if (TempFv->FvExtHeader !=3D NULL) { + free (TempFv->FvExtHeader); + } + + // + // Free encapsulate data; + // + EncapData1 =3D TempFv->EncapData; + + while (EncapData1 !=3D NULL) { + + EncapData2 =3D EncapData1; + EncapData1 =3D EncapData1->NextNode; + + if (EncapData2->Data !=3D NULL) { + free (EncapData2->Data); + } + if (EncapData2->FvExtHeader !=3D NULL) { + free(EncapData2->FvExtHeader); + } + free (EncapData2); + EncapData2 =3D NULL; + } + + EncapData1 =3D NULL; + + free (TempFv); + TempFv =3D NULL; + + } while (CurrentFv !=3D NULL); + + CurrentFv =3D NULL; + free (Fd); + Fd =3D 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 =3D NULL; + CompressedFile =3D NULL; + UnCompressedBuffer =3D NULL; + CompressedBuffer =3D NULL; + TempName =3D NULL; + TemDir =3D NULL; + TemString =3D NULL; + UnCompressedSize =3D 0; + CompressedSize =3D 0; + + if ( InputFileName =3D=3D NULL || + OutPutFileName =3D=3D NULL) { + printf ("Error while generate compressed section!\n"); + return EFI_INVALID_PARAMETER; + } + + if (CompressionType =3D=3D EFI_STANDARD_COMPRESSION) { + UnCompressFile =3D fopen (InputFileName, "rb"); + if (UnCompressFile =3D=3D NULL) { + printf ("Error while open file %s \n", InputFileName); + return EFI_ABORTED; + } + + TemDir =3D 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 =3D GenTempFile (); + TempName=3D LibFilenameStrExtended (strrchr(TemString, OS_SEP), TemDir= , "comp"); + free (TemString); + TemString =3D NULL; + if (TempName =3D=3D NULL) { + fclose(UnCompressFile); + return EFI_ABORTED; + } + + CompressedFile =3D fopen (TempName, "wb+"); + if (CompressedFile =3D=3D 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 =3D ftell(UnCompressFile); + + fseek(UnCompressFile,0,SEEK_SET); + + UnCompressedBuffer =3D malloc (UnCompressedSize); + + if (UnCompressedBuffer =3D=3D NULL) { + printf ("Out of resource, memory allocation failed. \n"); + fclose (CompressedFile); + fclose(UnCompressFile); + free (TempName); + return EFI_OUT_OF_RESOURCES; + } + + CompressedBuffer =3D malloc (UnCompressedSize); + + if (CompressedBuffer =3D=3D 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, UnCompres= sFile) =3D=3D (size_t) UnCompressedSize) { + CompressedSize =3D UnCompressedSize; + + Status =3D 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, CompressedFi= le) !=3D (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, OutPutFil= eName, NULL, NULL, NULL, "PI_STD"); + free (TempName); + TempName =3D NULL; + + } else if (CompressionType =3D=3D EFI_NOT_COMPRESSED) { + + LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_COMPRESSION, OutP= utFileName, 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] =3D { + "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 =3D NULL; + FirstGuidTool =3D NULL; + LastGuidTool =3D NULL; + NewGuidTool =3D NULL; + Index =3D 0; + + for (Index =3D 0; Index < BUILD_IN_TOOL_COUNT; Index++) { + Tool =3D SplitStringByWhitespace (PreDefinedGuidedTool[Index]); + if ((Tool !=3D NULL) && + (Tool->Count =3D=3D 3) + ) { + Status =3D StringToGuid (Tool->Strings[0], &Guid); + if (!EFI_ERROR (Status)) { + NewGuidTool =3D malloc (sizeof (GUID_SEC_TOOL_ENTRY)); + if (NewGuidTool !=3D NULL) { + memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid)); + NewGuidTool->Name =3D CloneString(Tool->Strings[1]); + NewGuidTool->Path =3D CloneString(Tool->Strings[2]); + NewGuidTool->Next =3D NULL; + } else { + printf ( "Fail to allocate memory. \n"); + if (Tool !=3D NULL) { + FreeStringList (Tool); + } + return NULL; + } + if (FirstGuidTool =3D=3D NULL) { + FirstGuidTool =3D NewGuidTool; + } else { + LastGuidTool->Next =3D NewGuidTool; + } + LastGuidTool =3D NewGuidTool; + } + } else { + fprintf (stdout, "Error"); + } + if (Tool !=3D NULL) { + FreeStringList (Tool); + Tool =3D 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 =3D 0; + FvIndex2 =3D 0; + FvFoundFlag =3D FALSE; + + if (FdData =3D=3D NULL || FvId =3D=3D NULL) { + printf ( "Error while find FV in FD. \n"); + return EFI_INVALID_PARAMETER; + } + + *FvInFd =3D FdData->Fv; + + FvIndex1 =3D (UINT8) atoi (FvId + 2); + + while (FvInFd !=3D NULL) { + if (((*FvInFd)->FvName) !=3D NULL) { + FvIndex2 =3D (UINT8) atoi ((*FvInFd)->FvName + 2); + + if ((FvIndex2 <=3D FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 = >=3D FvIndex1)) { + FvFoundFlag =3D TRUE; + break; + } + if ((*FvInFd)->FvNext =3D=3D 0) { + break; + } + *FvInFd =3D (*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 =3D 0; + Buffer =3D NULL; + NewFvFile =3D NULL; + + if (OutputFileName =3D=3D NULL || PatchData =3D=3D NULL) { + return EFI_ABORTED; + } + + NewFvFile =3D fopen (OutputFileName, "rb+"); + if (NewFvFile =3D=3D NULL) { + return EFI_ABORTED; + } + + fseek(NewFvFile, 0, SEEK_SET); + fseek(NewFvFile, 0, SEEK_END); + + NewFvLength =3D 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 =3D (UINT8 *) malloc (PatchData->Length); + + if (Buffer =3D=3D NULL) { + fclose (NewFvFile); + return EFI_ABORTED; + } + + if (fread (Buffer, 1, (size_t) PatchData->Length, NewFvFile) !=3D (siz= e_t) PatchData->Length) { + fclose (NewFvFile); + free(Buffer); + return EFI_ABORTED; + } + + // + // The area used to patch data should be filled by 0xff. + // + for (Count =3D 0; Count< PatchData->Length; Count++) { + if (Buffer[Count] !=3D 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)= !=3D (size_t) PatchData->Length) { + fclose (NewFvFile); + return EFI_ABORTED; + } + + PatchData =3D PatchData->NextNode; + } while (PatchData !=3D 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 =3D 0; + ParentType =3D 0; + ParentLevel =3D 0; + Type =3D 0; + Level =3D 0; + FfsFoundFlag =3D FALSE; + ExtractionTool =3D NULL; + InputFileName =3D NULL; + OutputFileName =3D NULL; + IsLastLevelFfs =3D TRUE; + IsLeafFlagIgnore =3D FALSE; + FirstInFlag =3D TRUE; + FvGuidName =3D NULL; + + // + // Encapsulate from the lowest FFS file level. + // + LocalEncapData =3D FvInFd->EncapData; + Level =3D LocalEncapData->Level; + Type =3D LocalEncapData->Type; + + // + // Get FV Name GUID + // + + while (LocalEncapData !=3D NULL) { + // + // Has changed. + // + if (LocalEncapData->Level > Level) { + if (LocalEncapData->Type =3D=3D BFM_ENCAP_TREE_FFS) { + ParentLevel =3D Level; + ParentType =3D Type; + } + + Level =3D LocalEncapData->Level; + Type =3D LocalEncapData->Type; + } + + if (LocalEncapData->NextNode !=3D NULL) { + LocalEncapData =3D LocalEncapData->NextNode; + } else { + break; + } + } + + do { + switch (ParentType) { + case BFM_ENCAP_TREE_FV: + + // + // Generate FV.inf attributes. + // + InfFileName =3D LibFilenameStrExtended (strrchr(GenTempFile (), OS= _SEP), TemDir, "inf"); + + InfFile =3D fopen (InfFileName, "wt+"); + + if (InfFile =3D=3D NULL) { + printf ("Could not open inf file %s to store FV information. \n"= , InfFileName); + return EFI_ABORTED; + } + + LocalEncapData =3D FvInFd->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHea= derOffset !=3D 0) { + // + // FV GUID Name memory allocation + // + FvGuidName =3D (CHAR8 *) malloc (255); + + if (FvGuidName =3D=3D 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 =3D NULL; + } + + + if (ParentLevel =3D=3D 1) { + Status =3D LibFvHeaderOptionToStr(((EFI_FIRMWARE_VOLUME_HEADER *= )LocalEncapData->Data)->BlockMap, InfFile, TRUE); + } else { + Status =3D 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 !=3D NULL) { + free (FvGuidName); + } + return Status; + } + + Status =3D LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER = *)LocalEncapData->Data)->Attributes, InfFile); + + if (EFI_ERROR (Status)) { + printf ("Generate FV header attribute failed.\n"); + if (FvGuidName !=3D NULL) { + free (FvGuidName); + } + fclose (InfFile); + return Status; + } + if (LocalEncapData->FvExtHeader !=3D NULL) { + Status =3D LibGenExtFile(LocalEncapData->FvExtHeader, InfFile); + if (FvGuidName !=3D NULL) { + free (FvGuidName); + } + if (EFI_ERROR(Status)) { + printf("Generate FV EXT header failed.\n"); + fclose (InfFile); + return Status; + } + FvGuidName =3D NULL; + } + + // + // Found FFSs from Fv structure. + // + FfsFoundFlag =3D FALSE; + for (Index =3D 0; Index <=3D FvInFd->FfsNumbers; Index++) { + + // + // For the last level FFS, the level below FFSs we should not ca= re the IsLeaf Flag. + // + if (IsLastLevelFfs) { + IsLeafFlagIgnore =3D TRUE; + } else { + IsLeafFlagIgnore =3D FvInFd->FfsAttuibutes[Index].IsLeaf; + } + + if (FvInFd->FfsAttuibutes[Index].Level >=3D ParentLevel + 1 && I= sLeafFlagIgnore) { + if (FirstInFlag) { + Status =3D 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 =3D 0; + FirstInFlag =3D FALSE; + } else { + Status =3D LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Ind= ex].FfsName, InfFile, FALSE); + + if (EFI_ERROR (Status)) { + printf ("Error while generate FV inf file [files] sectio= n. \n"); + fclose (InfFile); + return Status; + } + + FvInFd->FfsAttuibutes[Index].Level =3D 0; + } + FfsFoundFlag =3D TRUE; + } + // + // Also add the sub FV + // + if (FvInFd->FfsAttuibutes[Index].Level - 1 =3D=3D ParentLevel+= 1) { + LocalEncapData =3D FvInFd->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel + 2) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + if (LocalEncapData->Type =3D=3D BFM_ENCAP_TREE_GUIDED_SECTIO= N) { + Status =3D LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Ind= ex].FfsName, InfFile, FALSE); + + if (EFI_ERROR (Status)) { + printf ("Error while generate FV inf file [files] sectio= n.\n"); + fclose (InfFile); + return Status; + } + + FvInFd->FfsAttuibutes[Index].Level =3D 0; + } + + } + } + + IsLastLevelFfs =3D FALSE; + FirstInFlag =3D TRUE; + if (!FfsFoundFlag) { + Status =3D LibAddFfsFileToFvInf (OutputFileName, InfFile, TRUE); + if (EFI_ERROR (Status)) { + printf ("Error while generate FV inf file [files] section.\n"); + fclose (InfFile); + return Status; + } + } + /* + if (OutputFileName !=3D NULL && FfsFoundFlag) { + Status =3D 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=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "FV"); + Status =3D LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileNam= e, FvGuidName); + if (FvGuidName !=3D NULL) { + free (FvGuidName); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Patch FIT Table Data or reset vector data if exist. + // + if ((FvInFd->PatchData !=3D NULL) && (1 =3D=3D ParentLevel)) { + Status =3D LibPatchResetVectorAndFitTableData(OutputFileName, Fv= InFd->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 !=3D NULL) { + InputFileName =3D OutputFileName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile ()= , OS_SEP), TemDir, "ffs"); + + LocalEncapData =3D FvInFd->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D Level) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + Status =3D LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOL= UME_IMAGE, InputFileName, OutputFileName, ((EFI_FFS_FILE_HEADER *)LocalEnca= pData->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 =3D OutputFileName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "compressed"); + + // + // Use the guided section header guid to find out compress applica= tion name. + // + LocalEncapData =3D FvInFd->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + ExtractionTool =3D + LookupGuidedSectionToolPath ( + mParsedGuidedSectionTools, + (EFI_GUID *)LocalEncapData->Data + ); + + Status =3D LibCreateGuidedSectionOriginalData (InputFileName, Extr= actionTool, OutputFileName); + + if (EFI_ERROR (Status)) { + printf ("Error while compress guided data. \n"); + return Status; + } + + InputFileName =3D OutputFileName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "guided"); + + Status =3D LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_GU= ID_DEFINED, OutputFileName, NULL, NULL, LibBfmGuidToStr((EFI_GUID *)LocalEn= capData->Data), NULL); + + if (EFI_ERROR (Status)) { + printf ("Error while generate guided section. \n"); + return Status; + } + + break; + case BFM_ENCAP_TREE_COMPRESS_SECTION: + if (OutputFileName !=3D NULL) { + InputFileName =3D OutputFileName; + + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile ()= , OS_SEP), TemDir, "comsec"); + + LocalEncapData =3D FvInFd->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + + Status =3D LibGenCompressedSection (InputFileName, OutputFileNam= e, *(UINT8 *)(LocalEncapData->Data)); + + if (EFI_ERROR (Status)) { + printf ("Error while generate compressed section. \n"); + return Status; + } + } + break; + case BFM_ENCAP_TREE_FV_SECTION: + InputFileName =3D OutputFileName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "sec"); + + Status =3D LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_FI= RMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, NULL); + + if (EFI_ERROR (Status)) { + printf ("Error while generate FV section. \n"); + return Status; + } + + InputFileName =3D OutputFileName; + OutputFileName=3D LibFilenameStrExtended (strrchr(GenTempFile (), = OS_SEP), TemDir, "sec"); + + // + // Make it alignment. + // + Status =3D LibCreateFfsSection(InputFileName, NULL, 0, OutputFileN= ame, 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 -=3D 1; + LocalEncapData =3D FvInFd->EncapData; + while (LocalEncapData->NextNode !=3D NULL) { + if (LocalEncapData->Level =3D=3D ParentLevel) { + ParentType =3D LocalEncapData->Type; + break; + } + LocalEncapData =3D LocalEncapData->NextNode; + } + } while (ParentLevel !=3D 0); + + + *OutputFile =3D 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 =3D 0; + FvIndex2 =3D 0; + FvFoundFlag =3D FALSE; + + if (FdData =3D=3D NULL || FvId =3D=3D NULL || FvInFd =3D=3D NULL) { + return EFI_ABORTED; + } + + *FvId =3D (*FvInFd)->FvName; + + FvIndex1 =3D (UINT8) atoi ((*FvInFd)->FvName + 2); + + *FvInFd =3D FdData->Fv; + + while (FvInFd !=3D NULL) { + if (((*FvInFd)->FvName) !=3D NULL) { + FvIndex2 =3D (UINT8) atoi ((*FvInFd)->FvName + 2); + + if ((FvIndex2 <=3D FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 = >=3D FvIndex1)) { + FvFoundFlag =3D TRUE; + break; + } + if ((*FvInFd)->FvNext =3D=3D 0) { + break; + } + *FvInFd =3D (*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 =3D NULL; + + if (FileName =3D=3D NULL) { + return 0; + } + File =3D fopen(FileName, "r"); + + if (File =3D=3D NULL) { + return 0; + } + fseek(File, 0L, SEEK_END); + Length =3D 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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BinFileManager.h" + +BOOLEAN mFvGuidIsSet =3D FALSE; +EFI_GUID mFvNameGuid =3D {0}; +CHAR8* mFvNameGuidString =3D NULL; +CHAR8* mGuidToolDefinition =3D "GuidToolDefinitionConf.ini"; + +// +// Store GUIDed Section guid->tool mapping +// +EFI_HANDLE mParsedGuidedSectionTools =3D 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 =3D NULL; + FileNamePath =3D NULL; +#ifndef __GNUC__ + CurDir =3D strtok (PathList,";"); +#else + CurDir =3D strtok (PathList,":"); +#endif + while (CurDir !=3D NULL) { + FileNamePath =3D (char *)calloc( + strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileNa= me) + 1, + sizeof(char) + ); + if (FileNamePath =3D=3D NULL) { + return NULL; + } + sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName); + if (access (FileNamePath, 0) !=3D -1) { + return FileNamePath; + } +#ifndef __GNUC__ + CurDir =3D strtok(NULL, ";"); +#else + CurDir =3D strtok(NULL, ":"); +#endif + free (FileNamePath); + FileNamePath =3D NULL; + } + return NULL; +} + +/** + + Show the FD image layout information. Only display the modules with UI n= ame. + + @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 =3D NULL; + CurrentFv =3D NULL; + FvImage =3D NULL; + FvSize =3D 0; + BytesRead =3D 0; + FfsCount =3D 0; + FvCount =3D 0; + LastFvNumber =3D 0; + + // + // Check the FD file name/path. + // + if (FdInName =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Open the file containing the FV + // + InputFile =3D fopen (FdInName, "rb"); + if (InputFile =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D LibFindFvInFd (InputFile, &LocalFdData); + + if (EFI_ERROR(Status)) { + fclose (InputFile); + return EFI_ABORTED; + } + + CurrentFv =3D LocalFdData->Fv; + + do { + + memset (CurrentFv->FvName, '\0', _MAX_PATH); + + if (LastFvNumber =3D=3D 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) !=3D 0) { + fclose (InputFile); + LibBfmFreeFd( LocalFdData); + return EFI_ABORTED; + } + + Status =3D 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 buff= er + // + fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET); + + FvImage =3D (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize); + + if (FvImage =3D=3D NULL) { + fclose (InputFile); + LibBfmFreeFd( LocalFdData); + return EFI_ABORTED; + } + + BytesRead =3D fread (FvImage, 1, FvSize, InputFile); + if ((unsigned int) BytesRead !=3D FvSize) { + free (FvImage); + fclose (InputFile); + LibBfmFreeFd( LocalFdData); + return EFI_ABORTED; + } + + // + // Collect FV information each by each. + // + Status =3D LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &FfsCount, Vie= wFlag, FALSE); + free (FvImage); + FvImage =3D NULL; + if (EFI_ERROR (Status)) { + fclose (InputFile); + LibBfmFreeFd( LocalFdData); + return Status; + } + FvCount =3D CurrentFv->FvLevel; + LastFvNumber =3D LastFvNumber+FvCount; + + FfsCount =3D 0; + + CurrentFv =3D CurrentFv->FvNext; + + } while (CurrentFv !=3D NULL); + + if (!ViewFlag) { + *FdData =3D 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 =3D 0; + FvEncapLevel =3D 0; + NewAddedFfsLevel =3D 0; + + FfsLevelFoundFlag =3D FALSE; + FirstInFlag =3D TRUE; + FdData =3D NULL; + FvInFd =3D NULL; + LocalEncapData =3D NULL; + NewFdFile =3D NULL; + NewFvFile =3D NULL; + Buffer =3D NULL; + TemDir =3D NULL; + LocalEncapDataTemp =3D NULL; + OutputFileName =3D NULL; + FvId =3D NULL; + FvGuidExisted =3D FALSE; + + // + // Get the size of ffs file to be inserted. + // + NewFfsLength =3D GetFileSize(NewFile); + + Status =3D 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 s= etting. + // If the FV image with -g GUID can't be found, the storage is still sav= ed into the BFV and report warning message. + // + FvInFd =3D FdData->Fv; + do { + if (mFvGuidIsSet && FvInFd->IsInputFvFlag) { + FvGuidExisted =3D TRUE; + break; + } + FvInFd =3D FvInFd->FvNext; + } while (FvInFd !=3D 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 =3D FdData->Fv; + do { + if ((FvGuidExisted && mFvGuidIsSet && FvInFd->IsInputFvFlag) || ((!FvG= uidExisted || (!mFvGuidIsSet)) && FvInFd->IsBfvFlag)) { + + Status =3D 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 =3D FvInFd->EncapData; + + while (LocalEncapData !=3D NULL && !FfsLevelFoundFlag ) { + if (LocalEncapData->Type =3D=3D BFM_ENCAP_TREE_FV) { + if (FvEncapLevel =3D=3D ((UINT8) atoi (FvId + 2) - (UINT8) atoi = (FvInFd->FvName + 2))) { + // + // Found the FFS level in this FV. + // + LocalEncapDataTemp =3D LocalEncapData; + while (LocalEncapDataTemp !=3D NULL) { + if (LocalEncapDataTemp->Type =3D=3D BFM_ENCAP_TREE_FFS) { + NewAddedFfsLevel =3D LocalEncapDataTemp->Level; + FfsLevelFoundFlag =3D TRUE; + break; + } + if (LocalEncapDataTemp->NextNode !=3D NULL) { + LocalEncapDataTemp =3D LocalEncapDataTemp->NextNode; + } else { + break; + } + } + } + FvEncapLevel ++; + } + + if (LocalEncapData->NextNode =3D=3D NULL) { + break; + } else { + LocalEncapData =3D LocalEncapData->NextNode; + } + } + + // + // Add the new file into FV. + // + FvInFd->FfsNumbers +=3D 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] =3D= 0; + FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level =3D NewAddedFfsLev= el; + + TemDir =3D 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 =3D LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName); + + if (EFI_ERROR (Status)) { + printf("Error. The boot firmware volume (BFV) has only the spare s= pace 0x%lx bytes. But the default setting data takes 0x%llx bytes, which ca= n't be inserted into BFV. \n",(unsigned long) GetBfvPadSize (), (unsigned l= ong long)NewFfsLength); + LibBfmFreeFd(FdData); + return Status; + } + + if (FirstInFlag) { + // + // Write New Fv file into the NewFd file. + // + Status =3D LibCreateNewFdCopy (FdInName, FdOutName); + if (EFI_ERROR (Status)) { + printf("Error while copy from %s to %s file. \n", FdInName, FdOu= tName); + LibBfmFreeFd(FdData); + return Status; + } + FirstInFlag =3D FALSE; + } + + NewFdFile =3D fopen (FdOutName, "rb+"); + if (NewFdFile =3D=3D NULL) { + printf("Error while create FD file %s. \n", FdOutName); + LibBfmFreeFd(FdData); + return EFI_ABORTED; + } + + NewFvFile =3D fopen (OutputFileName, "rb+"); + + if (NewFvFile =3D=3D 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 =3D ftell(NewFvFile); + + fseek(NewFvFile,0,SEEK_SET); + + Buffer =3D malloc ((size_t)NewFvLength); + + if (Buffer =3D=3D NULL) { + printf ("Error while allocate resource! \n"); + fclose(NewFdFile); + fclose(NewFvFile); + LibBfmFreeFd(FdData); + return EFI_ABORTED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) !=3D (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 <=3D FvInFd->FvHeader->FvLength) { + if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) !=3D (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 large= r than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) New= FvLength, (unsigned long long) FvInFd->FvHeader->FvLength); + free (Buffer); + fclose(NewFdFile); + fclose(NewFvFile); + LibBfmFreeFd(FdData); + return EFI_ABORTED; + } + + fclose(NewFdFile); + fclose(NewFvFile); + free (Buffer); + Buffer =3D NULL; + + } + FvInFd =3D FvInFd->FvNext; + } while (FvInFd !=3D NULL); + + + LibBfmFreeFd(FdData); + + if (TemDir =3D=3D 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 =3D 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 =3D 0; + FdIsUpdate =3D FALSE; + FirstInFlag =3D TRUE; + FdData =3D NULL; + FvInFd =3D NULL; + NewFdFile =3D NULL; + NewFvFile =3D NULL; + Buffer =3D NULL; + TemDir =3D NULL; + OutputFileName =3D NULL; + FvId =3D NULL; + FfsFile =3D NULL; + BytesRead =3D 0; + ReplaceSameFv =3D FALSE; + FvGuidExisted =3D FALSE; + + // + // Get the size of ffs file to be inserted. + // + NewFfsLength =3D GetFileSize(NewFile); + // + // Get FFS GUID + // + FfsFile =3D fopen (NewFile, "rb"); + if (FfsFile =3D=3D NULL) { + printf ("Error while read %s.\n", NewFile); + return EFI_ABORTED; + } + fseek (FfsFile, 0, SEEK_SET); + BytesRead =3D fread (&EfiNewAddToBfvGuid, 1, sizeof(EFI_GUID), FfsFile); + fclose (FfsFile); + if (BytesRead !=3D sizeof(EFI_GUID)) { + printf ("Error while read the GUID from %s.\n", NewFile); + return EFI_ABORTED; + } + Status =3D 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 sett= ing. + // 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 sa= ved into the same FV image and report warning message. + // + if (!mFvGuidIsSet) { + ReplaceSameFv =3D TRUE; + } + FvInFd =3D FdData->Fv; + do { + if (mFvGuidIsSet && FvInFd->IsInputFvFlag) { + FvGuidExisted =3D TRUE; + break; + } + FvInFd =3D FvInFd->FvNext; + } while (FvInFd !=3D NULL); + + if (mFvGuidIsSet && !FvGuidExisted) { + printf ("Fv image with the specified FV Name Guid %s can't be found in= current FD.\n", mFvNameGuidString); + ReplaceSameFv =3D TRUE; + LibBfmFreeFd(FdData); + return EFI_ABORTED; + } + // + // Interate to insert or replace default setting to Fv + // + FvInFd =3D FdData->Fv; + do { + FvToBeUpdate =3D FALSE; + if (mFvGuidIsSet && FvInFd->IsInputFvFlag) { + FvToBeUpdate =3D TRUE; + } + + Status =3D LibLocateBfv (FdData, &FvId, &FvInFd); + + if (EFI_ERROR (Status)) { + printf("Error while locate BFV from FD.\n"); + LibBfmFreeFd(FdData); + return Status; + } + + Index =3D 0; + while (Index <=3D 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 =3D TRUE; + } + break; + } + Index ++; + } + + if (FvToBeUpdate || (Index <=3D FvInFd->FfsNumbers)) { + if (FvToBeUpdate) { + FdIsUpdate =3D TRUE; + if (Index <=3D 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_PAT= H - 1); + FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] =3D 0; + } else { + FfsLevelFoundFlag =3D FALSE; + FvEncapLevel =3D 0; + NewAddedFfsLevel =3D 0; + // + // Determine the new added ffs file level in the FV. + // + LocalEncapData =3D FvInFd->EncapData; + + while (LocalEncapData !=3D NULL && !FfsLevelFoundFlag ) { + if (LocalEncapData->Type =3D=3D BFM_ENCAP_TREE_FV) { + if (FvEncapLevel =3D=3D ((UINT8) atoi (FvId + 2) - (UINT8) a= toi (FvInFd->FvName + 2))) { + // + // Found the FFS level in this FV. + // + LocalEncapDataTemp =3D LocalEncapData; + while (LocalEncapDataTemp !=3D NULL) { + if (LocalEncapDataTemp->Type =3D=3D BFM_ENCAP_TREE_FFS) { + NewAddedFfsLevel =3D LocalEncapDataTemp->Level; + FfsLevelFoundFlag =3D TRUE; + break; + } + if (LocalEncapDataTemp->NextNode !=3D NULL) { + LocalEncapDataTemp =3D LocalEncapDataTemp->NextNode; + } else { + break; + } + } + } + FvEncapLevel ++; + } + + if (LocalEncapData->NextNode =3D=3D NULL) { + break; + } else { + LocalEncapData =3D LocalEncapData->NextNode; + } + } + + // + // Add the new file into FV. + // + FvInFd->FfsNumbers +=3D 1; + memcpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFi= le, _MAX_PATH); + FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level =3D NewAddedFf= sLevel; + } + } else { + // + // Remove original default data from FV. + // + FvInFd->FfsAttuibutes[Index].FfsName[0] =3D '\0'; + } + + if (TemDir =3D=3D NULL) { + TemDir =3D 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 =3D LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName); + + if (EFI_ERROR (Status)) { + printf("Error. The boot firmware volume (BFV) has only the spare s= pace 0x%lx bytes. But the default setting data takes 0x%llx bytes, which ca= n'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 =3D LibCreateNewFdCopy (FdInName, FdOutName); + if (EFI_ERROR (Status)) { + printf("Error while copy from %s to %s file. \n", FdInName, FdOu= tName); + LibBfmFreeFd(FdData); + return Status; + } + FirstInFlag =3D FALSE; + } + + NewFdFile =3D fopen (FdOutName, "rb+"); + if (NewFdFile =3D=3D NULL) { + printf("Error while create FD file %s. \n", FdOutName); + LibBfmFreeFd(FdData); + return EFI_ABORTED; + } + + NewFvFile =3D fopen (OutputFileName, "rb+"); + + if (NewFvFile =3D=3D 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 =3D ftell(NewFvFile); + + fseek(NewFvFile,0,SEEK_SET); + + Buffer =3D malloc ((size_t)NewFvLength); + + if (Buffer =3D=3D NULL) { + LibBfmFreeFd(FdData); + fclose (NewFdFile); + fclose (NewFvFile); + return EFI_ABORTED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) !=3D (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 <=3D FvInFd->FvHeader->FvLength) { + if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) !=3D (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 large= r than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) New= FvLength, (unsigned long long) FvInFd->FvHeader->FvLength); + free (Buffer); + LibBfmFreeFd(FdData); + fclose (NewFdFile); + fclose (NewFvFile); + return EFI_ABORTED; + } + + fclose(NewFdFile); + fclose(NewFvFile); + free (Buffer); + Buffer =3D NULL; + + } + FvInFd =3D FvInFd->FvNext; + } while (FvInFd !=3D NULL); + + LibBfmFreeFd(FdData); + + if (TemDir =3D=3D 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 =3D 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 =3D NULL; + PathList =3D NULL; + NewPathList =3D NULL; + EnvLen =3D 0; + + if (Argc <=3D 1) { + return -1; + } + FileName =3D Argv[0]; + // + // Save, skip filename arg + // + Argc--; + Argv++; + + if ((stricmp(Argv[0], "-v") =3D=3D 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[] =3D "/tmp/fileXXXXXX"; + UINTN Fdtmp; + Fdtmp =3D 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] =3D 0; + FileNameIndex =3D strlen (FullGuidToolDefinition); + while (FileNameIndex !=3D 0) { + FileNameIndex --; + if (FullGuidToolDefinition[FileNameIndex] =3D=3D OS_SEP) { + FullGuidToolDefinition[FileNameIndex] =3D 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 =3D getenv("PATH"); + if (PathList =3D=3D NULL) { + Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not ex= ist", NULL); + return -1; + } + EnvLen =3D strlen(PathList); + NewPathList =3D (char *)calloc( + strlen (".") + + strlen (";") + + strlen (FullGuidToolDefinition) + + strlen (";") + + EnvLen + + 1, + sizeof(char) + ); + if (NewPathList =3D=3D NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + PathList =3D NULL; + free (PathList); + return -1; + } +#ifndef __GNUC__ + sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList); +#else + sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList); +#endif + + PathList =3D NULL; + free (PathList); + // + // Load Guid Tools definition + // + InFilePath =3D SearchConfigFromPathList(NewPathList, mGuidToolDefinition= ); + free (NewPathList); + if (InFilePath !=3D NULL) { + printf ("\nThe Guid Tool Definition of BfmLib comes from the '%s'. \n"= , InFilePath); + mParsedGuidedSectionTools =3D ParseGuidedSectionToolsFile (InFilePath); + free (InFilePath); + } else { + // + // Use the pre-defined standard guided tools. + // + printf ("\nThe Guid Tool Definition of BfmLib comes from the build-in de= fault configuration. \n"); + mParsedGuidedSectionTools =3D LibPreDefinedGuidedTools (); + } + + // + // BfmLib -e FdName.Fd + // + if ((stricmp(Argv[0], "-e") =3D=3D 0)) { + + if (Argc !=3D 2) { + return -1; + } + // + // Extract FFS files. + // + Status =3D BfmImageView (Argv[1], NULL, FALSE, &FdData); + + if (EFI_ERROR (Status)) { + return -1; + } + + if (FdData =3D=3D NULL) { + return -1; + } + + LibBfmFreeFd(FdData); + + } else if ((stricmp(Argv[0], "-i") =3D=3D 0)) { + // + // Insert FFS files to BFV + // BfmLib -i InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid + // + if (Argc =3D=3D 6) { + mFvGuidIsSet =3D TRUE; + mFvNameGuidString =3D Argv[5]; + StringToGuid (Argv[5], &mFvNameGuid); + Argc -=3D 2; + } + if (Argc !=3D 4) { + return -1; + } + Status =3D BfmImageAdd(Argv[1], Argv[2], Argv[3]); + + if (EFI_ERROR (Status)) { + return -1; + } + + } else if ((stricmp(Argv[0], "-r") =3D=3D 0)) { + // + // Replace FFS files in BFV + // BfmLib -r InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid + // + if (Argc =3D=3D 6) { + mFvGuidIsSet =3D TRUE; + mFvNameGuidString =3D Argv[5]; + StringToGuid (Argv[5], &mFvNameGuid); + Argc -=3D 2; + } + if (Argc !=3D 4) { + return -1; + } + Status =3D 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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _BIN_FILE_MANAGER_ +#define _BIN_FILE_MANAGER_ + +#ifdef __GNUC__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#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 infor= mation + // + 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.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +MAKEROOT ?=3D $(EDK_TOOLS_PATH)/Source/C + +APPNAME =3D BfmLib + +LIBS =3D -lCommon + +OBJECTS =3D BinFileManager.o BfmLib.o + +include $(MAKEROOT)/Makefiles/app.makefile diff --git a/Platform/Intel/Tools/BfmLib/Makefile b/Platform/Intel/Tools/Bf= mLib/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.
+# SPDX-License-Identifier: BSD-2-Clause-Patent# +## +!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common + +APPNAME =3D BfmLib + +LIBS =3D $(LIB_PATH)\Common.lib + +OBJECTS =3D BinFileManager.obj BfmLib.obj + +!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app + --=20 2.18.0.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#42670): https://edk2.groups.io/g/devel/message/42670 Mute This Topic: https://groups.io/mt/32154335/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Wed May 1 07:02:20 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+42671+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+42671+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1561080422; cv=none; d=zoho.com; s=zohoarc; b=NLWMUPkG5WWUMiElYgNv2VhVZ5s0MIqmnpXJgbC53qOh4102Jr1jIozfVvb2u3zpueZLXNw2Plumg1UGDaYI9SuMIJ/kCnUdQgWh3N4ak2hli4k4B6bM66Fm8lx/+Vb9PGPk/obqoUPHwqcTqHbSrNndFES6n/iBkfO1eDBDioQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1561080422; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To:ARC-Authentication-Results; bh=8iCA9a7RMTvNFENviXAFAtoaTYkZXQq0ZTIjJF6yqC8=; b=C0PS4DW4N/IutZP7FELzGWgJf5cprM6T7k2W8kVrFRcWBmGXCAzaEyHEG7UdFzQ4S7w3nVhqnZH2rLc4lr1knZfHa3PPcjKoMNWAhVnOsYIfGxvhIpJsDXkMvN95iq/poswoeNpC8QzSdHjEw1wucDvi4jC36zlst6mOsl5FVhE= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+42671+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1561080422530691.9110881670912; Thu, 20 Jun 2019 18:27:02 -0700 (PDT) Return-Path: X-Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by groups.io with SMTP; Thu, 20 Jun 2019 18:27:00 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 Jun 2019 18:26:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,398,1557212400"; d="scan'208";a="358723186" X-Received: from shenglei-dev.ccr.corp.intel.com ([10.239.158.52]) by fmsmga005.fm.intel.com with ESMTP; 20 Jun 2019 18:26:54 -0700 From: "Zhang, Shenglei" To: devel@edk2.groups.io Cc: Bob Feng , Liming Gao Subject: [edk2-devel] [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE Date: Fri, 21 Jun 2019 09:26:40 +0800 Message-Id: <20190621012643.9352-4-shenglei.zhang@intel.com> In-Reply-To: <20190621012643.9352-1-shenglei.zhang@intel.com> References: <20190621012643.9352-1-shenglei.zhang@intel.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,shenglei.zhang@intel.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1561080421; bh=cCM8vZkSOefc81T0ECzxrmRiV1LSNeejxzv3a3yvdKo=; h=Cc:Date:From:Reply-To:Subject:To; b=NbxKWeHjtO4cLmlbsqKFexaGb/pA2pXyh7OFx4PsqDt9RvmtXfGRaImqKVbFrcGj4T/ 43JFF6jjT2cgrhNl77Mz/n5VhqJ+2VMOvqlVDVtpepD31vB6pcU1THpuOg+U7rrMaRPfB luU8Aczx9Uj4g8ea5w4SIVMysE0w8R7gFhg= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" FCE is a tool to retrieve and change HII configuration data in Firmware Device(*.fd) files. https://bugzilla.tianocore.org/show_bug.cgi?id=3D1848 Cc: Bob Feng Cc: Liming Gao Signed-off-by: Shenglei Zhang --- 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.
+ 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 =3D EFI_FFS_BFV_FOR_MULTIPLATFORM_= GUID; +EFI_GUID gEfiFfsBfvForMultiPlatformGuid2 =3D 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 =3D NULL; + + if (Guid =3D=3D NULL) { + return NULL; + } + + Buffer =3D (CHAR8 *) malloc (36 + 1); + + if (Buffer =3D=3D 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 =3D NULL; + SystemCommand =3D malloc ( + strlen (GENSEC_RAW) + + strlen ("EFI_SECTION_RAW") + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D SystemCommand) { + return EFI_OUT_OF_RESOURCES; + } + sprintf ( + SystemCommand, + GENSEC_RAW, + "EFI_SECTION_RAW", + InputFilePath, + OutputFilePath + ); + ReturnValue =3D system (SystemCommand); + free(SystemCommand); + + if (ReturnValue !=3D 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 =3D NULL; + GuidStr =3D NULL; + FilePathStr =3D NULL; + StrLen =3D 0; + + FilePathFormatStr =3D " -i \""; + + for (Index =3D 0; InputFilePaths[Index] !=3D NULL; Index++) { + Size =3D strlen (FilePathFormatStr) + strlen (InputFilePaths[Index]) += 2; // 2 menas "" " + if (FilePathStr =3D=3D NULL) { + FilePathStr =3D malloc (Size); + if (NULL =3D=3D FilePathStr) { + return EFI_OUT_OF_RESOURCES; + } + } else { + FilePathStr =3D realloc (FilePathStr, StrLen + Size); + if (NULL =3D=3D FilePathStr) { + return EFI_OUT_OF_RESOURCES; + } + } + memset (FilePathStr + StrLen, ' ', Size); + memcpy (FilePathStr + StrLen, FilePathFormatStr, strlen(FilePathFormat= Str)); + memcpy(FilePathStr + StrLen + strlen(FilePathFormatStr), InputFilePath= s[Index], strlen(InputFilePaths[Index])); + StrLen +=3D Size; + *(FilePathStr + StrLen - 2) =3D '\"'; + } + if (FilePathStr =3D=3D NULL) { + return EFI_ABORTED; + } + *(FilePathStr + StrLen - 1)=3D '\0'; + + + if (SizeOptimized) { + GuidStr =3D LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid2); + } else { + GuidStr =3D LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid); + } + if (NULL =3D=3D GuidStr) { + free (FilePathStr); + return EFI_OUT_OF_RESOURCES; + } + SystemCommandFormatString =3D "GenFfs -t %s %s -g %s -o \"%s\""; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + + strlen ("EFI_FV_FILETYPE_FREEFORM") + + strlen (FilePathStr) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 1 + ); + if (NULL =3D=3D 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 =3D system (SystemCommand); + free(SystemCommand); + free (FilePathStr); + free (GuidStr); + + if (ReturnValue !=3D 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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _BINARY_CREATE_H_ +#define _BINARY_CREATE_H_ 1 + +#include +#include "Compress.h" +#include "Decompress.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "FirmwareVolumeBufferLib.h" +#include "OsPath.h" +#include "ParseGuidedSectionTools.h" +#include "StringFuncs.h" +#include "ParseInf.h" +#include +#include +#include +#include +#include +#include +#include +#include + +//1AE42876-008F-4161-B2B7-1C0D15C5EF43 +#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID \ + { 0x1ae42876, 0x008f, 0x4161, { 0xb2, 0xb7, 0x1c, 0xd, 0x15, 0xc5, 0xef,= 0x43 }} + +extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid; + +// {003E7B41-98A2-4BE2-B27A-6C30C7655225} +#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID2 \ + { 0x3e7b41, 0x98a2, 0x4be2, { 0xb2, 0x7a, 0x6c, 0x30, 0xc7, 0x65, 0x52, = 0x25 }} + +extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid2; + +typedef UINT64 SKU_ID; + +typedef struct { + UINT32 Offset:24; + UINT32 Value:8; +} PCD_DATA_DELTA; + +typedef struct { + SKU_ID SkuId; + UINT16 DefaultId; + UINT8 Reserved[6]; +} PCD_DEFAULT_INFO; + +typedef struct { + // + // Full size, it must be at 8 byte alignment. + // + UINT32 DataSize; + // + // HeaderSize includes HeaderSize fields and DefaultInfo arrays + // + UINT32 HeaderSize; + // + // DefaultInfo arrays those have the same default setting. + // + PCD_DEFAULT_INFO DefaultInfo[1]; + // + // Default data is stored as variable storage or the array of DATA_DELTA. + // +} PCD_DEFAULT_DATA; + +#define PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE SIGNATURE_32('N', 'S', 'D', = 'B') + +typedef struct { + // + // PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE + // + UINT32 Signature; + // + // Length of the taken default buffer + // + UINT32 Length; + // + // Length of the total reserved buffer + // + UINT32 MaxLength; + // + // Reserved for 8 byte alignment + // + UINT32 Reserved; + // one or more PCD_DEFAULT_DATA +} PCD_NV_STORE_DEFAULT_BUFFER_HEADER; + +// +// NvStoreDefaultValueBuffer layout: +// +-------------------------------------+ +// | PCD_NV_STORE_DEFAULT_BUFFER_HEADER | +// +-------------------------------------+ +// | PCD_DEFAULT_DATA (DEFAULT, Standard)| +// +-------------------------------------+ +// | PCD_DATA_DELTA (DEFAULT, Standard)| +// +-------------------------------------+ +// | ...... | +// +-------------------------------------+ +// | PCD_DEFAULT_DATA (SKU A, Standard) | +// +-------------------------------------+ +// | PCD_DATA_DELTA (SKU A, Standard) | +// +-------------------------------------+ +// | ...... | +// +-------------------------------------+ +// + +#pragma pack(1) + +typedef struct { + UINT16 Offset; + UINT8 Value; +} DATA_DELTA; + +#pragma pack() + +/** + Create the Ras section in FFS + + @param[in] InputFilePath The input file path and name. + @param[in] OutputFilePath The output file path and name. + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +CreateRawSection ( + IN CHAR8* InputFilePath, + IN CHAR8* OutputFilePath + ); + +/** + Create the Ras type of FFS + + @param[in] InputFilePath .efi file, it's optional unless process PE/= TE section. + @param[in] OutputFilePath .te or .pe file + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +CreateRawFfs ( + IN CHAR8** InputFilePaths, + IN CHAR8* OutputFilePath, + IN BOOLEAN SizeOptimized + ); + +#endif + diff --git a/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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GNUC__ +#include "windows.h" +#else +#include +#include +#include +#endif +#include "BinaryParse.h" +#include "BinaryCreate.h" +#include "VariableCommon.h" +#include "FirmwareVolumeBufferLib.h" + +extern G_EFI_FD_INFO gEfiFdInfo; +extern EFI_HANDLE mParsedGuidedSectionTools; +extern CHAR8 mInputFdName[MAX_FILENAME_LEN]; + +// +// The Guid to sign the position of Vfr and Uni array in FV +// +EFI_GUID gVfrArrayAttractGuid =3D EFI_VFR_ATTRACT= _GUID; +EFI_GUID gUniStrArrayAttractGuid =3D EFI_UNI_STR_ATT= RACT_GUID; +EFI_GUID gEfiSystemNvDataFvGuid =3D EFI_SYSTEM_NVDA= TA_FV_GUID; +EFI_GUID gEfiCrc32GuidedSectionExtractionProtocolGuid =3D EFI_CRC32_GUIDE= D_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 =3D 0; + + if (ThreeByteLength =3D=3D NULL) { + return 0; + } + + Length =3D *((UINT32 *) ThreeByteLength); + Length =3D Length & 0x00FFFFFF; + + return Length; +} + +/** + Generate the unique template filename. +**/ +CHAR8 * +GenTempFile ( + VOID + ) +{ + CHAR8 *TemString; + TemString =3D NULL; +#ifndef __GNUC__ + TemString =3D CloneString (tmpnam (NULL)); +#else + CHAR8 tmp[] =3D "/tmp/fileXXXXXX"; + UINTN Fdtmp; + Fdtmp =3D mkstemp(tmp); + TemString =3D 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 =3D 0; + + while (gEfiFdInfo.FfsArray[Index] !=3D NULL) { + if (memcmp (gEfiFdInfo.FfsArray[Index], FfsImage, sizeof (EFI_GUID)) = =3D=3D 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 =3D ActualSize; + while ((OccupiedSize & (Alignment - 1)) !=3D 0) { + OccupiedSize++; + } + + return OccupiedSize; +} + + +/** + Parses FFS Sections, and remove the FFS headers. Tis function olny handl= e 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 informat= ions + + @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 =3D NULL; + SectionLength =3D 0; + CompressedBuffer =3D NULL; + CompressedLength =3D 0; + UncompressedBuffer =3D NULL; + UncompressedLength =3D 0; + CompressionType =3D 0; + ScratchSize =3D 0; + ScratchBuffer =3D NULL; + Status =3D EFI_SUCCESS; + DstSize =3D 0; + ExtractionTool =3D NULL; + ToolInputFile =3D NULL; + ToolOutputFile =3D NULL; + SystemCommandFormatString =3D NULL; + SystemCommand =3D NULL; + + // + // Jump the FFS header + // + if (IsFfsOrEfi) { + SectionBuffer =3D SectionBuffer + sizeof (EFI_FFS_FILE_HEADER); + BufferLength =3D BufferLength - sizeof (EFI_FFS_FILE_HEADER); + } + ParsedLength =3D 0; + HasDepexSection =3D FALSE; + ExtractionTool =3D NULL; + ToolOutputLength =3D 0; + ToolOutputBuffer =3D NULL; + + (*EfiBufferHeader)->Length =3D BufferLength; + + while (ParsedLength < BufferLength) { + Ptr =3D SectionBuffer + ParsedLength; + + SectionLength =3D Get3ByteLength (((EFI_COMMON_SECTION_HEADER *) Ptr)-= >Size); + Type =3D ((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 se= ction + // header worth of 0xFF bytes. + // + if ((SectionLength =3D=3D 0xffffff) && (Type =3D=3D 0xff)) { + ParsedLength +=3D 4; + continue; + } + + switch (Type) { + + case EFI_SECTION_PE32: + case EFI_SECTION_TE: + // + //Got the correct address + // + (*EfiBufferHeader)->BufferBase =3D (UINTN)(Ptr + sizeof (EFI_COMMON_S= ECTION_HEADER)); + return EFI_SUCCESS; + + case EFI_SECTION_RAW: + case EFI_SECTION_PIC: + break; + + case EFI_SECTION_USER_INTERFACE: + HasDepexSection =3D 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 =3D TRUE; + break; + + case EFI_SECTION_VERSION: + break; + case EFI_SECTION_COMPRESSION: + UncompressedBuffer =3D NULL; + CompressedLength =3D SectionLength - sizeof (EFI_COMPRESSION_SECT= ION); + UncompressedLength =3D ((EFI_COMPRESSION_SECTION *) Ptr)->Uncompres= sedLength; + CompressionType =3D ((EFI_COMPRESSION_SECTION *) Ptr)->Compressi= onType; + + if (CompressionType =3D=3D EFI_NOT_COMPRESSED) { + if (CompressedLength !=3D UncompressedLength) { + Error ( + NULL, + 0, + 0, + "file is not compressed, but the compressed length does not ma= tch the uncompressed length", + NULL + ); + return EFI_ABORTED; + } + + UncompressedBuffer =3D Ptr + sizeof (EFI_COMPRESSION_SECTION); + } else if (CompressionType =3D=3D EFI_STANDARD_COMPRESSION) { + GetInfoFunction =3D EfiGetInfo; + DecompressFunction =3D EfiDecompress; + CompressedBuffer =3D Ptr + sizeof (EFI_COMPRESSION_SECTION); + + Status =3D GetInfoFunction ( + CompressedBuffer, + CompressedLength, + &DstSize, + &ScratchSize + ); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error getting compression info from compr= ession section", NULL); + return EFI_ABORTED; + } + + if (DstSize !=3D UncompressedLength) { + Error (NULL, 0, 0003, "compression error in the compression sect= ion", NULL); + return EFI_ABORTED; + } + + ScratchBuffer =3D malloc (ScratchSize); + if (ScratchBuffer =3D=3D NULL) { + return EFI_ABORTED; + } + UncompressedBuffer =3D malloc (UncompressedLength); + if (UncompressedBuffer =3D=3D NULL) { + free (ScratchBuffer); + return EFI_ABORTED; + } + memset (UncompressedBuffer, 0, UncompressedLength); + + Status =3D DecompressFunction ( + CompressedBuffer, + CompressedLength, + UncompressedBuffer, + UncompressedLength, + ScratchBuffer, + ScratchSize + ); + free (ScratchBuffer); + if (Status !=3D 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 =3D ParseSection (FALSE, UncompressedBuffer, UncompressedLeng= th, EfiBufferHeader); + if (Status !=3D EFI_SUCCESS) { + Error (NULL, 0, 0003, "failed to parse section", NULL); + free (UncompressedBuffer); + UncompressedBuffer =3D NULL; + } else { + return EFI_SUCCESS; + } + // + // Store the allocate memory address for UncompressedBuffer + // + if (UncompressedBuffer !=3D NULL) { + (*EfiBufferHeader)->UncompressedBuffer[(*EfiBufferHeader)->UnCompr= essIndex] =3D (UINTN) UncompressedBuffer; + (*EfiBufferHeader)->UnCompressIndex =3D (*EfiBufferHeader)->UnComp= ressIndex + 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 =3D ParseSection ( + FALSE, + SectionBuffer + ((EFI_GUID_DEFINED_SECTION *) Ptr)->Dat= aOffset, + BufferLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->Data= Offset, + EfiBufferHeader + ); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "parse of CRC32 GUIDED section failed", NU= LL); + return EFI_ABORTED; + } else { + return EFI_SUCCESS; + } + } else { + ExtractionTool =3D LookupGuidedSectionToolPath ( + mParsedGuidedSectionTools, + &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDef= initionGuid + ); + + if (ExtractionTool !=3D NULL) { + ToolInputFile =3D GenTempFile (); + ToolOutputFile =3D GenTempFile (); + // + // Construction 'system' command string + // + SystemCommandFormatString =3D "%s -d -o \"%s\" \"%s\""; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) \ + + strlen (ExtractionTool) \ + + strlen (ToolInputFile) \ + + strlen (ToolOutputFile) \ + + 1 + ); + if (SystemCommand =3D=3D NULL) { + free (ExtractionTool); + free (ToolInputFile); + free (ToolOutputFile); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "%s -d -o \"%s\" \"%s\"", + ExtractionTool, + ToolOutputFile, + ToolInputFile + ); + free (ExtractionTool); + + Status =3D PutFileImage ( + ToolInputFile, + (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) Ptr)->Da= taOffset, + SectionLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->D= ataOffset + ); + + if (HasDepexSection) { + HasDepexSection =3D FALSE; + } + + system (SystemCommand); + remove (ToolInputFile); + free (ToolInputFile); + ToolInputFile =3D NULL; + free (SystemCommand); + SystemCommand =3D NULL; + + if (EFI_ERROR (Status)) { + Error ("FCE", 0, 0004, "unable to decoded GUIDED section", NUL= L); + free (ToolOutputFile); + return EFI_ABORTED; + } + + Status =3D GetFileImage ( + ToolOutputFile, + (CHAR8 **)&ToolOutputBuffer, + &ToolOutputLength + ); + remove (ToolOutputFile); + free (ToolOutputFile); + ToolOutputFile =3D NULL; + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + } + Status =3D 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 +=3D SectionLength; + // + // We make then next section begin on a 4-byte boundary + // + ParsedLength =3D 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 >=3D Len || Len - *Offset <=3D sizeof (EFI_GUID)) { + return FALSE; + } + + for (NextOffset =3D *Offset; NextOffset < Len - sizeof (EFI_GUID); NextO= ffset++) { + if (CompareGuid(Guid, (EFI_GUID*)(Data + NextOffset)) =3D=3D 0) { + *Offset =3D 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 m= atching 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 =3D=3D NULL) || (Fv =3D=3D NULL) || (Guid =3D=3D NULL) || Len = =3D=3D 0 ){ + return EFI_ABORTED; + } + + LocalFv =3D Fv; + Flag =3D 0; + Section =3D NULL; + Key =3D 0; + + if (NumOfMatchGuid !=3D NULL) { + *NumOfMatchGuid =3D 0; + } + + SectionStart =3D (VOID*)((UINTN)LocalFv + FvBufGetFfsHeaderSize(LocalFv)= ); + TotalSectionsSize =3D Len - FvBufGetFfsHeaderSize(LocalFv); + while (TRUE) { + Status =3D FvBufFindNextSection ( + SectionStart, + TotalSectionsSize, + &Key, + (VOID **)&Section + ); + if (Section =3D=3D NULL || EFI_ERROR (Status)) { + break; + } + + if (EFI_SECTION_RAW =3D=3D Section->Type) { + if ((*(UINT32 *)Section->Size & 0xffffff) =3D=3D 0xffffff) { + SecLen =3D ((EFI_RAW_SECTION2 *)Section)->ExtendedSize; + SecHdr =3D sizeof(EFI_RAW_SECTION2); + } else { + SecLen =3D *(UINT32 *)Section->Size & 0xffffff; + SecHdr =3D sizeof(EFI_RAW_SECTION); + } + if (SecLen <=3D SecHdr || SecLen - SecHdr < sizeof(EFI_GUID)) { + continue; + } + RawData =3D (UINT8 *)Section + SecHdr; + NextOffset =3D 0; + while (GetNextOffset(RawData, Guid, SecLen - SecHdr, &NextOffset)) { + Flag =3D 1; + if ((NumOfMatchGuid !=3D NULL) && (Offset !=3D NULL)) { + if (*NumOfMatchGuid =3D=3D 0) { + *Offset =3D malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM); + if (*Offset =3D=3D NULL) { + return EFI_ABORTED; + } + memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM); + } + *(*Offset + *NumOfMatchGuid) =3D NextOffset + (RawData - (UINT8 = *)Fv); + (*NumOfMatchGuid)++; + } else { + return EFI_SUCCESS; + } + } + } + } + + if( Flag =3D=3D 0 ) { + return EFI_ABORTED; + } + return EFI_SUCCESS; +} + +/** + Search the VfrBin Base address. + + According the known GUID gVfrArrayAttractGuid to get the base address fr= om 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 =3D 0; + Status =3D EFI_SUCCESS; + VirOffValue =3D 0; + + if ((Fv =3D=3D NULL) || (Offset =3D=3D NULL)) { + return EFI_ABORTED; + } + Status =3D GetAddressByGuid ( + Fv, + &gVfrArrayAttractGuid, + Length, + Offset, + NumOfMachingOffset + ); + if (Status !=3D EFI_SUCCESS) { + return EFI_ABORTED; + } + + while (Index < *NumOfMachingOffset) { + // + // Got the virOffset after the GUID + // + VirOffValue =3D *(UINTN *)((UINTN)Fv + *(*Offset + Index)); + // + //Transfer the offset to the VA address. One modules may own more VfrB= in address. + // + *(*Offset + Index) =3D (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 =3D 0; + Status =3D EFI_SUCCESS; + VirOffValue =3D 0; + + if ((Fv =3D=3D NULL) || (Offset =3D=3D NULL)) { + return EFI_ABORTED; + } + Status =3D GetAddressByGuid ( + Fv, + &gUniStrArrayAttractGuid, + Length, + Offset, + &NumOfMachingOffset + ); + if (Status !=3D EFI_SUCCESS) { + return EFI_ABORTED; + } + // + //Transfer the offset to the VA address. There is only one UniArray in o= ne modules. + // + if (NumOfMachingOffset =3D=3D 1) { + VirOffValue =3D *(UINTN *)((UINTN)Fv + **Offset); + **Offset =3D (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 =3D EFI_SUCCESS; + Offset =3D 0; + if (Fv =3D=3D NULL) { + printf ("The FV is NULL."); + return EFI_ABORTED; + } + while (Offset < (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER))){ + NvStoreHeader =3D (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)((UINT8*)Fv + = Offset); + if (NvStoreHeader->Signature =3D=3D PCD_NV_STORE_DEFAULT_BUFFER_SIGNAT= URE) { + gEfiFdInfo.ExistNvStoreDatabase =3D TRUE; + gEfiFdInfo.NvStoreDatabase =3D (UINT8 *) NvStoreHeader; + break; + } + Offset++; + } + if (Offset =3D=3D (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) = || gEfiFdInfo.ExistNvStoreDatabase !=3D 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 ma= tching 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 =3D=3D NULL) || (Fv =3D=3D NULL) || (Guid =3D=3D NULL) ){ + return EFI_ABORTED; + } + + Flag =3D 0; + NextOffset =3D 0; + + if (NumOfMatchGuid !=3D NULL) { + *NumOfMatchGuid =3D 0; + } + while (GetNextOffset(Fv, Guid, Len, &NextOffset)) { + Flag =3D 1; + if (NumOfMatchGuid !=3D NULL && Offset !=3D NULL) { + if (*NumOfMatchGuid =3D=3D 0) { + *Offset =3D malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM); + if (*Offset =3D=3D NULL) { + return EFI_ABORTED; + } + memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM); + } + *(*Offset + *NumOfMatchGuid) =3D NextOffset; + (*NumOfMatchGuid)++; + } else { + return EFI_SUCCESS; + } + } + + if( Flag =3D=3D 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 =3D EFI_SUCCESS; + Index =3D 0; + + if ((Fv =3D=3D NULL) || (Offset =3D=3D NULL)) { + printf ("The FV or offset is NULL."); + return EFI_ABORTED; + } + Status =3D GetVariableAddressByGuid ( + Fv, + &gEfiSystemNvDataFvGuid, + Length, + Offset, + NumOfMachingOffset + ); + if (Status !=3D EFI_SUCCESS) { + return EFI_ABORTED; + } + // + //Transfer the offset to the VA address. + // + while (Index < *NumOfMachingOffset) { + *(*Offset + Index) =3D (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 =3D=3D NULL) || (FvSize =3D=3D NULL)) { + return EFI_ABORTED; + } + // + // Read the header + // + fread ( + &FfsHeader, + sizeof (EFI_FFS_FILE_HEADER), + 1, + InputFile + ); + Type =3D FfsHeader.Type; + + if (Type =3D=3D EFI_FV_FILETYPE_DRIVER) { + *FvSize =3D *(UINT32 *)FfsHeader.Size & 0xffffff; + } else if (Type =3D=3D EFI_FV_FILETYPE_APPLICATION) { + *FvSize =3D *(UINT32 *)FfsHeader.Size & 0xffffff; + } else if (Type =3D=3D EFI_FV_FILETYPE_FREEFORM) { + *FvSize =3D *(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 =3D=3D NULL) || (FvSize =3D=3D NULL)) { + return EFI_ABORTED; + } + *FvSize =3D 0; + // + // Get the total size of FD file (Fixed the length) + // + fseek(InputFile,0,SEEK_END); + *FvSize =3D ftell(InputFile); + fseek(InputFile,0,SEEK_SET); + + if (*FvSize =3D=3D 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 =3D NULL; + Address =3D NULL; + BytesRead =3D 0; + Status =3D EFI_SUCCESS; + + InFile =3D fopen (FileName,"rb"); + if (InFile =3D=3D NULL) { + return NULL; + } + // + // Determine the size of FV + // + Status =3D ReadFdHeader (InFile, Size); + if (Status !=3D EFI_SUCCESS) { + fclose (InFile); + return NULL; + } + // + // Allocate a buffer for the FV image + // + Address =3D malloc (*Size); + if (Address =3D=3D 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 =3D fread (Address, 1, *Size, InFile); + fclose (InFile); + if ((UINTN) BytesRead !=3D *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 =3D NULL; + FdSize =3D 0; + Status =3D EFI_SUCCESS; + EfiVarAddr =3D NULL; + NumOfMachingVar =3D 0; + Index =3D 0; + GotFlag =3D TRUE; + Variable =3D NULL; + + FdImage =3D ReadFileToMemory (mInputFdName, &FdSize); + if (FdImage =3D=3D NULL) { + return EFI_ABORTED; + } + if (!UqiIsSet) { + Status =3D SearchNvStoreDatabaseInFd(FdImage, FdSize); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + } + Status =3D SearchEfiVarInFFS ( + FdImage, + FdSize, + &EfiVarAddr, + &NumOfMachingVar + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Check the signature "_FVH" + // + Index =3D 0; + GotFlag =3D FALSE; + + while (Index < NumOfMachingVar) { + Variable =3D (EFI_FIRMWARE_VOLUME_HEADER *)(*(EfiVarAddr + Index) - 0x= 20); + if (Variable->Signature =3D=3D 0x4856465F) { + AuthencitatedMonotonicOrNot =3D CheckMonotonicBasedVarStore ((UINT8= *)Variable + Variable->HeaderLength); + AuthencitatedBasedTimeOrNot =3D CheckTimeBasedVarStoreOrNot ((UINT8= *)Variable + Variable->HeaderLength); + NormalOrNot =3D CheckNormalVarStoreOrNot ((UINT8 *)= Variable + Variable->HeaderLength); + if (AuthencitatedMonotonicOrNot || AuthencitatedBasedTimeOrNot || No= rmalOrNot) { + GotFlag =3D TRUE; + gEfiFdInfo.EfiVariableAddr =3D (UINTN)Variable; + break; + } + } + Index++; + } + free (EfiVarAddr); + if (!GotFlag) { + return EFI_ABORTED; + } + gEfiFdInfo.Fd =3D FdImage; + gEfiFdInfo.FdSize =3D 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 =3D NULL; + CurFolderName =3D NULL; + Status =3D EFI_SUCCESS; + MaxFileNameLen =3D 0; + Index =3D 0; + FileSize =3D 0; + BytesRead =3D 0; + FfsImage =3D NULL; + FfsFile =3D NULL; + + MaxFileNameLen =3D strlen (FolderName) + MAX_FILENAME_LEN; + CurFolderName =3D (CHAR8 *)calloc( + strlen (FolderName) + strlen (OS_SEP_STR) + strlen ("= *.*")+ 1, + sizeof(CHAR8) + ); + if (CurFolderName =3D=3D NULL) { + return EFI_BUFFER_TOO_SMALL; + } + strcpy (CurFolderName, FolderName); + strcat (CurFolderName, OS_SEP_STR); + strcat (CurFolderName, "*.*"); + FileName =3D (CHAR8 *)calloc( + MaxFileNameLen, + sizeof(CHAR8) + ); + if (FileName =3D=3D NULL) { + free (CurFolderName); + return EFI_BUFFER_TOO_SMALL; + } + +#ifndef __GNUC__ + if((FindHandle =3D FindFirstFile(CurFolderName, &FindFileData)) !=3D INV= ALID_HANDLE_VALUE){ + do { + memset (FileName, 0, MaxFileNameLen); + if ((strcmp (FindFileData.cFileName, ".") =3D=3D 0) + || (strcmp (FindFileData.cFileName, "..") =3D=3D 0) + ) { + continue; + } + if (strlen(FolderName) + strlen ("\\") + strlen (FindFileData.cFileN= ame) > MAX_FILENAME_LEN - 1) { + Status =3D EFI_ABORTED; + goto Done; + } + snprintf (FileNameArry, MAX_FILENAME_LEN, "%s%c%s", FolderName, OS_S= EP, FindFileData.cFileName); + FfsFile =3D fopen (FileNameArry, "rb"); + if (FfsFile =3D=3D NULL) { + Status =3D EFI_ABORTED; + goto Done; + } + Status =3D ReadFfsHeader (FfsFile, (UINT32 *)&FileSize); + if (EFI_ERROR (Status)) { + fclose (FfsFile); + Status =3D EFI_SUCCESS; + continue; + } + // + // Allocate a buffer for the FFS file + // + FfsImage =3D malloc (FileSize); + if (FfsImage =3D=3D NULL) { + fclose (FfsFile); + Status =3D EFI_BUFFER_TOO_SMALL; + goto Done; + } + // + // Seek to the start of the image, then read the entire FV to the bu= ffer + // + fseek (FfsFile, 0, SEEK_SET); + BytesRead =3D fread (FfsImage, 1, FileSize, FfsFile); + fclose (FfsFile); + + if ((UINTN) BytesRead !=3D FileSize) { + free (FfsImage); + Status =3D EFI_ABORTED; + goto Done; + } + // + // Check whether exists the storage ffs in BFV for multi-platform mo= de + // + if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImag= e) =3D=3D 0) { + *ExistStorageInBfv =3D TRUE; + *SizeOptimized =3D FALSE; + gEfiFdInfo.StorageFfsInBfv =3D FfsImage; + continue; + } + // + // Check whether exists the optimized storage ffs in BFV for multi-p= latform mode + // + if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsIma= ge) =3D=3D 0) { + *ExistStorageInBfv =3D TRUE; + *SizeOptimized =3D TRUE; + gEfiFdInfo.StorageFfsInBfv =3D FfsImage; + continue; + } + // + // Check whether current FFS includes IFR + // + Status =3D GetAddressByGuid ( + FfsImage, + &gVfrArrayAttractGuid, + FileSize, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + free (FfsImage); + Status =3D EFI_SUCCESS; + } else { + // + // Check whether existed same IFR binary. If existed, not insert th= e new one. + // + if (NotExistSameFfsIfr (FfsImage)) { + gEfiFdInfo.FfsArray[Index] =3D FfsImage; + gEfiFdInfo.Length[Index++] =3D FileSize; + } + } + + } while (FindNextFile (FindHandle, &FindFileData)); + FindClose(FindHandle); + } else { + Status =3D EFI_ABORTED; + goto Done; + } + +Done: + free (CurFolderName); + free (FileName); + +#else + if((pDir =3D opendir(FolderName)) !=3D NULL){ + while ((pDirent =3D readdir(pDir)) !=3D NULL){ + memset (FileName, 0, MaxFileNameLen); + if ((strcmp (pDirent->d_name, ".") =3D=3D 0) + || (strcmp (pDirent->d_name, "..") =3D=3D 0) + ) { + continue; + } + sprintf (FileNameArry, "%s%c%s", FolderName, OS_SEP, pDirent->d_name= ); + FfsFile =3D fopen (FileNameArry, "rb"); + Status =3D ReadFfsHeader (FfsFile, (UINT32 *)&FileSize); + if (EFI_ERROR (Status)) { + fclose (FfsFile); + Status =3D EFI_SUCCESS; + continue; + } + // + // Allocate a buffer for the FFS file + // + FfsImage =3D malloc (FileSize); + if (FfsImage =3D=3D NULL) { + fclose (FfsFile); + Status =3D EFI_BUFFER_TOO_SMALL; + goto Done; + } + // + // Seek to the start of the image, then read the entire FV to the bu= ffer + // + fseek (FfsFile, 0, SEEK_SET); + BytesRead =3D fread (FfsImage, 1, FileSize, FfsFile); + fclose (FfsFile); + + if ((UINTN) BytesRead !=3D FileSize) { + free (FfsImage); + Status =3D EFI_ABORTED; + goto Done; + } + // + // Check whether exists the storage ffs in BFV for multi-platform mo= de + // + if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImag= e) =3D=3D 0) { + *ExistStorageInBfv =3D TRUE; + *SizeOptimized =3D FALSE; + gEfiFdInfo.StorageFfsInBfv =3D FfsImage; + continue; + } + // + // Check whether exists the optimized storage ffs in BFV for multi-p= latform mode + // + if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsIma= ge) =3D=3D 0) { + *ExistStorageInBfv =3D TRUE; + *SizeOptimized =3D TRUE; + gEfiFdInfo.StorageFfsInBfv =3D FfsImage; + continue; + } + // + // Check whether current FFS includes IFR + // + Status =3D GetAddressByGuid ( + FfsImage, + &gVfrArrayAttractGuid, + FileSize, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + free (FfsImage); + Status =3D EFI_SUCCESS; + } else { + // + // Check whether existed same IFR binary. If existed, not insert th= e new one. + // + if (NotExistSameFfsIfr (FfsImage)) { + gEfiFdInfo.FfsArray[Index] =3D FfsImage; + gEfiFdInfo.Length[Index++] =3D FileSize; + } + } + + } + closedir(pDir); + } else { + Status =3D 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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef _BINARY_PARSE_H_ +#define _BINARY_PARSE_H_ 1 + +#include +#include "Compress.h" +#include "Decompress.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "FirmwareVolumeBufferLib.h" +#include "OsPath.h" +#include "ParseGuidedSectionTools.h" +#include "StringFuncs.h" +#include "ParseInf.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +#define OS_SEP '/' +#define OS_SEP_STR "/" +#else +#define OS_SEP '\\' +#define OS_SEP_STR "\\" +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif + +#define TEMP_DIR_NAME "Temp" +#define MAX_FILENAME_LEN 200 +#define MAX_MATCH_GUID_NUM 100 +#define MAX_EFI_IN_FFS_NUM 100 + +typedef struct { + VOID *Fd; + UINT32 FdSize; + UINTN EfiVariableAddr; + UINTN Length[MAX_EFI_IN_FFS_NUM]; + VOID *FfsArray[MAX_EFI_IN_FFS_NUM]; + VOID *StorageFfsInBfv; + VOID *NvStoreDatabase; + BOOLEAN ExistNvStoreDatabase; +} G_EFI_FD_INFO; + +/// +///Define the structure for th sections +/// +typedef struct { + UINTN BufferBase; + UINTN UncompressedBuffer[MAX_EFI_IN_FFS_NUM]; + UINTN Length; + UINT8 UnCompressIndex; +} EFI_SECTION_STRUCT; + +// {d0bc7cb4-6a47-495f-aa11-710746da06a2} +#define EFI_VFR_ATTRACT_GUID \ +{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0x= a2 } } + +// {8913C5E0-33F6-4d86-9BF1-43EF89FC0666} +#define EFI_UNI_STR_ATTRACT_GUID \ +{ 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0= x66 } } + +// {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 handl= e 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 informat= ions + + @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 fr= om 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/C= ommon.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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include "Common.h" + +#define WARNING_STATUS_NUMBER 4 +#define ERROR_STATUS_NUMBER 24 + +CONST CHAR8 mHexStr[] =3D {'0','1','2','3','4','5','6','7','8','9','A','B'= ,'C','D','E','F'}; + +CONST CHAR8 *mStatusString[] =3D { + "Success", // RETURN_SUCCESS =3D 0 + "Warning Unknown Glyph", // RETURN_WARN_UNKNOWN_GLYPH =3D 1 + "Warning Delete Failure", // RETURN_WARN_DELETE_FAILURE =3D 2 + "Warning Write Failure", // RETURN_WARN_WRITE_FAILURE =3D 3 + "Warning Buffer Too Small", // RETURN_WARN_BUFFER_TOO_SMALL =3D 4 + "Load Error", // RETURN_LOAD_ERROR =3D 1 = | MAX_BIT + "Invalid Parameter", // RETURN_INVALID_PARAMETER =3D 2 = | MAX_BIT + "Unsupported", // RETURN_UNSUPPORTED =3D 3 = | MAX_BIT + "Bad Buffer Size", // RETURN_BAD_BUFFER_SIZE =3D 4 = | MAX_BIT + "Buffer Too Small", // RETURN_BUFFER_TOO_SMALL, =3D 5 = | MAX_BIT + "Not Ready", // RETURN_NOT_READY =3D 6 = | MAX_BIT + "Device Error", // RETURN_DEVICE_ERROR =3D 7 = | MAX_BIT + "Write Protected", // RETURN_WRITE_PROTECTED =3D 8 = | MAX_BIT + "Out of Resources", // RETURN_OUT_OF_RESOURCES =3D 9 = | MAX_BIT + "Volume Corrupt", // RETURN_VOLUME_CORRUPTED =3D 10= | MAX_BIT + "Volume Full", // RETURN_VOLUME_FULL =3D 11= | MAX_BIT + "No Media", // RETURN_NO_MEDIA =3D 12= | MAX_BIT + "Media changed", // RETURN_MEDIA_CHANGED =3D 13= | MAX_BIT + "Not Found", // RETURN_NOT_FOUND =3D 14= | MAX_BIT + "Access Denied", // RETURN_ACCESS_DENIED =3D 15= | MAX_BIT + "No Response", // RETURN_NO_RESPONSE =3D 16= | MAX_BIT + "No mapping", // RETURN_NO_MAPPING =3D 17= | MAX_BIT + "Time out", // RETURN_TIMEOUT =3D 18= | MAX_BIT + "Not started", // RETURN_NOT_STARTED =3D 19= | MAX_BIT + "Already started", // RETURN_ALREADY_STARTED =3D 20= | MAX_BIT + "Aborted", // RETURN_ABORTED =3D 21= | MAX_BIT + "ICMP Error", // RETURN_ICMP_ERROR =3D 22= | MAX_BIT + "TFTP Error", // RETURN_TFTP_ERROR =3D 23= | MAX_BIT + "Protocol Error" // RETURN_PROTOCOL_ERROR =3D 24= | MAX_BIT +}; + +/** + Copies one Null-terminated Unicode string to another Null-terminated Uni= code + string and returns the new Unicode string. + + This function copies the contents of the Unicode string Source to the Un= icode + 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 =3D NULL; + + if ((Destination =3D=3D NULL) || ((UINTN) Destination % 2 !=3D 0)) { + return NULL; + } + + ReturnValue =3D Destination; + while (*Source !=3D 0) { + *(Destination++) =3D *(Source++); + } + *Destination =3D 0; + return ReturnValue; +} + +/** + Returns the length of a Null-terminated Unicode string. + + This function returns the number of Unicode characters in the Null-termi= nated + 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 =3D=3D NULL) { + return 0; + } + for (Length =3D 0; *String !=3D 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 t= han + 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 f= irst + 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 !=3D L'\0') && (*FirstString =3D=3D *SecondString))= { + FirstString++; + SecondString++; + } + return *FirstString - *SecondString; +} + +/** + Concatenates one Null-terminated Unicode string to another Null-terminat= ed + Unicode string, and returns the concatenated Unicode string. + + This function concatenates two Null-terminated Unicode strings. The cont= ents + of Null-terminated Unicode string Source are concatenated to the end of + Null-terminated Unicode string Destination. The Null-terminated concaten= ated + 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 m= ore + than PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and Source contains more t= han + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and concatenating Destinat= ion + 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) !=3D 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) !=3D 0); + ASSERT (FceStrSize (SearchString) !=3D 0); + + if (*SearchString =3D=3D L'\0') { + return (CHAR16 *) String; + } + + while (*String !=3D L'\0') { + SearchStringTmp =3D SearchString; + FirstMatch =3D String; + + while ((*String =3D=3D *SearchStringTmp) + && (*String !=3D L'\0')) { + String++; + SearchStringTmp++; + } + + if (*SearchStringTmp =3D=3D L'\0') { + return (CHAR16 *) FirstMatch; + } + + if (*String =3D=3D L'\0') { + return NULL; + } + + String =3D 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 Un= icode + string Destination, and returns Destination. The function terminates the + Unicode string Destination by appending a Null-terminator character at t= he end. + The caller is responsible to make sure Destination points to a buffer wi= th 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 =3D NULL; + + if ((Destination =3D=3D NULL) || (Source =3D=3D NULL) || (strlen (Source= ) =3D=3D 0)) { + return NULL; + } + ReturnValue =3D Destination; + while (*Source !=3D '\0') { + *(Destination++) =3D (CHAR16) *(Source++); + } + // + // End the Destination with a NULL. + // + *Destination =3D '\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 a= n 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 strin= g 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 =3D 0; + do { + Value =3D (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Re= mainder); + *(++Buffer) =3D mHexStr[Remainder]; + } while (Value !=3D 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 !=3D 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 !=3D 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 =3D 0; Index < Length && Buffer < EndBuffer; Index++) { + *Buffer =3D (CHAR8) Character; + if (Increment !=3D 1) { + *(Buffer + 1) =3D (CHAR8)(Character >> 8); + } + Buffer +=3D Increment; + } + + return Buffer; +} + +/** + Worker function that produces a Null-terminated string in an output buff= er + based on a Null-terminated format string and a VA_LIST argument list. + + VSPrint function to process format and place the results in Buffer. Sinc= e 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 a= ll. + + @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 consume= d by + processing Format. + @param[in] BaseListMarker BASE_LIST style variable argument list consu= med + by processing Format. + + @return The number of characters printed not including the Null-terminat= or. + 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 funct= ion. + // Nearly identical logic is found in the BasePrintLib and + // DxePrintLibPrint2Protocol (both PrintLib instances). + // + + if ((Flags & COUNT_ONLY_NO_PRINT) !=3D 0) { + if (BufferSize =3D=3D 0) { + Buffer =3D NULL; + } + } else { + // + // We can run without a Buffer for counting only. + // + if (BufferSize =3D=3D 0) { + return 0; + } + ASSERT (Buffer !=3D NULL); + } + + if ((Flags & OUTPUT_UNICODE) !=3D 0) { + BytesPerOutputCharacter =3D 2; + } else { + BytesPerOutputCharacter =3D 1; + } + + LengthToReturn =3D 0; + + // + // Reserve space for the Null terminator. + // + BufferSize--; + OriginalBuffer =3D Buffer; + + // + // Set the tag for the end of the input Buffer. + // + EndBuffer =3D Buffer + BufferSize * BytesPerOutputCharacter; + + if ((Flags & FORMAT_UNICODE) !=3D 0) { + // + // Make sure format string cannot contain more than PcdMaximumUnicodeS= tringLength + // Unicode characters if PcdMaximumUnicodeStringLength is not zero. + // + ASSERT (FceStrSize ((CHAR16 *) Format) !=3D 0); + BytesPerFormatCharacter =3D 2; + FormatMask =3D 0xffff; + } else { + // + // Make sure format string cannot contain more than PcdMaximumAsciiStr= ingLength + // Ascii characters if PcdMaximumAsciiStringLength is not zero. + // + ASSERT (strlen (Format) + 1 !=3D 0); + BytesPerFormatCharacter =3D 1; + FormatMask =3D 0xff; + } + + // + // Get the first character from the format string + // + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMa= sk; + + // + // Loop until the end of the format string is reached or the output buff= er is full + // + while (FormatCharacter !=3D 0 && Buffer < EndBuffer) { + // + // Clear all the flag bits except those that may have been passed in + // + Flags &=3D (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT); + + // + // Set the default width to zero, and the default precision to 1 + // + Width =3D 0; + Precision =3D 1; + Prefix =3D 0; + Comma =3D FALSE; + ZeroPad =3D FALSE; + Count =3D 0; + Digits =3D 0; + + switch (FormatCharacter) { + case '%': + // + // Parse Flags and Width + // + for (Done =3D FALSE; !Done; ) { + Format +=3D BytesPerFormatCharacter; + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) & Fo= rmatMask; + switch (FormatCharacter) { + case '.': + Flags |=3D PRECISION; + break; + case '-': + Flags |=3D LEFT_JUSTIFY; + break; + case '+': + Flags |=3D PREFIX_SIGN; + break; + case ' ': + Flags |=3D PREFIX_BLANK; + break; + case ',': + Flags |=3D COMMA_TYPE; + break; + case 'L': + case 'l': + Flags |=3D LONG_TYPE; + break; + case '*': + if ((Flags & PRECISION) =3D=3D 0) { + Flags |=3D PAD_TO_WIDTH; + if (BaseListMarker =3D=3D NULL) { + Width =3D VA_ARG (VaListMarker, UINTN); + } else { + Width =3D BASE_ARG (BaseListMarker, UINTN); + } + } else { + if (BaseListMarker =3D=3D NULL) { + Precision =3D VA_ARG (VaListMarker, UINTN); + } else { + Precision =3D BASE_ARG (BaseListMarker, UINTN); + } + } + break; + case '0': + if ((Flags & PRECISION) =3D=3D 0) { + Flags |=3D PREFIX_ZERO; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + for (Count =3D 0; ((FormatCharacter >=3D '0') && (FormatCharact= er <=3D '9')); ){ + Count =3D (Count * 10) + FormatCharacter - '0'; + Format +=3D BytesPerFormatCharacter; + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) = & FormatMask; + } + Format -=3D BytesPerFormatCharacter; + if ((Flags & PRECISION) =3D=3D 0) { + Flags |=3D PAD_TO_WIDTH; + Width =3D Count; + } else { + Precision =3D Count; + } + break; + + case '\0': + // + // Make no output if Format string terminates unexpectedly when + // looking up for flag, width, precision and type. + // + Format -=3D BytesPerFormatCharacter; + Precision =3D 0; + // + // break skipped on purpose. + // + default: + Done =3D TRUE; + break; + } + } + + // + // Handle each argument type + // + switch (FormatCharacter) { + case 'p': + // + // Flag space, +, 0, L & l are invalid for type p. + // + Flags &=3D ~(PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE); + if (sizeof (VOID *) > 4) { + Flags |=3D LONG_TYPE; + } + case 'X': + Flags |=3D PREFIX_ZERO; + // + // break skipped on purpose + // + case 'x': + Flags |=3D RADIX_HEX; + // + // break skipped on purpose + // + case 'd': + if ((Flags & LONG_TYPE) =3D=3D 0) { + // + // 'd','x', and 'X' that are not preceded by 'l' or 'L' are assu= med to be type "int". + // This assumption is made so the format string definition is co= mpatible 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 m= ore important, and + // provides an implementation that is compatible with that large= st possible set of CPU + // architectures. This is why the type "int" is used in this on= e case. + // + if (BaseListMarker =3D=3D NULL) { + Value =3D VA_ARG (VaListMarker, int); + } else { + Value =3D BASE_ARG (BaseListMarker, int); + } + } else { + if (BaseListMarker =3D=3D NULL) { + Value =3D VA_ARG (VaListMarker, INT64); + } else { + Value =3D BASE_ARG (BaseListMarker, INT64); + } + } + if ((Flags & PREFIX_BLANK) !=3D 0) { + Prefix =3D ' '; + } + if ((Flags & PREFIX_SIGN) !=3D 0) { + Prefix =3D '+'; + } + if ((Flags & COMMA_TYPE) !=3D 0) { + Comma =3D TRUE; + } + if ((Flags & RADIX_HEX) =3D=3D 0) { + Radix =3D 10; + if (Comma) { + Flags &=3D (~PREFIX_ZERO); + Precision =3D 1; + } + if (Value < 0) { + Flags |=3D PREFIX_SIGN; + Prefix =3D '-'; + Value =3D -Value; + } + } else { + Radix =3D 16; + Comma =3D FALSE; + if ((Flags & LONG_TYPE) =3D=3D 0 && Value < 0) { + // + // 'd','x', and 'X' that are not preceded by 'l' or 'L' are as= sumed 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 tha= t 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 lar= gest possible set of CPU + // architectures. This is why the type "unsigned int" is used= in this one case. + // + Value =3D (unsigned int)Value; + } + } + // + // Convert Value to a reversed string + // + Count =3D BasePrintLibValueToString (ValueBuffer, Value, Radix) - = ValueBuffer; + if (Value =3D=3D 0 && Precision =3D=3D 0) { + Count =3D 0; + } + ArgumentString =3D (CHAR8 *)ValueBuffer + Count; + + Digits =3D Count % 3; + if (Digits !=3D 0) { + Digits =3D 3 - Digits; + } + if (Comma && Count !=3D 0) { + Count +=3D ((Count - 1) / 3); + } + if (Prefix !=3D 0) { + Count++; + Precision++; + } + Flags |=3D ARGUMENT_REVERSED; + ZeroPad =3D TRUE; + if ((Flags & PREFIX_ZERO) !=3D 0) { + if ((Flags & LEFT_JUSTIFY) =3D=3D 0) { + if ((Flags & PAD_TO_WIDTH) !=3D 0) { + if ((Flags & PRECISION) =3D=3D 0) { + Precision =3D Width; + } + } + } + } + break; + + case 's': + case 'S': + Flags |=3D ARGUMENT_UNICODE; + // + // break skipped on purpose + // + case 'a': + if (BaseListMarker =3D=3D NULL) { + ArgumentString =3D VA_ARG (VaListMarker, CHAR8 *); + } else { + ArgumentString =3D BASE_ARG (BaseListMarker, CHAR8 *); + } + if (ArgumentString =3D=3D NULL) { + Flags &=3D (~ARGUMENT_UNICODE); + ArgumentString =3D ""; + } + // + // Set the default precision for string to be zero if not specifie= d. + // + if ((Flags & PRECISION) =3D=3D 0) { + Precision =3D 0; + } + break; + + case 'c': + if (BaseListMarker =3D=3D NULL) { + Character =3D VA_ARG (VaListMarker, UINTN) & 0xffff; + } else { + Character =3D BASE_ARG (BaseListMarker, UINTN) & 0xffff; + } + ArgumentString =3D (CHAR8 *)&Character; + Flags |=3D ARGUMENT_UNICODE; + break; + + case 'g': + if (BaseListMarker =3D=3D NULL) { + TmpGuid =3D VA_ARG (VaListMarker, EFI_GUID *); + } else { + TmpGuid =3D BASE_ARG (BaseListMarker, EFI_GUID *); + } + if (TmpGuid =3D=3D NULL) { + ArgumentString =3D ""; + } else { + GuidData1 =3D ReadUnaligned32 (&(TmpGuid->Data1)); + GuidData2 =3D FceReadUnaligned16 (&(TmpGuid->Data2)); + GuidData3 =3D 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 =3D ValueBuffer; + } + break; + + case 't': + if (BaseListMarker =3D=3D NULL) { + TmpTime =3D VA_ARG (VaListMarker, TIME *); + } else { + TmpTime =3D BASE_ARG (BaseListMarker, TIME *); + } + if (TmpTime =3D=3D NULL) { + ArgumentString =3D ""; + } else { + BasePrintLibSPrint ( + ValueBuffer, + MAXIMUM_VALUE_CHARACTERS, + 0, + "%02d/%02d/%04d %02d:%02d", + TmpTime->Month, + TmpTime->Day, + TmpTime->Year, + TmpTime->Hour, + TmpTime->Minute + ); + ArgumentString =3D ValueBuffer; + } + break; + + case 'r': + if (BaseListMarker =3D=3D NULL) { + Status =3D VA_ARG (VaListMarker, RETURN_STATUS); + } else { + Status =3D BASE_ARG (BaseListMarker, RETURN_STATUS); + } + ArgumentString =3D ValueBuffer; + if (RETURN_ERROR (Status)) { + // + // Clear error bit + // + Index =3D Status & ~MAX_BIT; + if (Index > 0 && Index <=3D ERROR_STATUS_NUMBER) { + ArgumentString =3D mStatusString [Index + WARNING_STATUS_NUMBE= R]; + } + } else { + Index =3D Status; + if (Index <=3D WARNING_STATUS_NUMBER) { + ArgumentString =3D mStatusString [Index]; + } + } + if (ArgumentString =3D=3D ValueBuffer) { + BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACT= ERS, 0, "%08X", Status); + } + break; + + case '\r': + Format +=3D BytesPerFormatCharacter; + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) & Fo= rmatMask; + if (FormatCharacter =3D=3D '\n') { + // + // Translate '\r\n' to '\r\n' + // + ArgumentString =3D "\r\n"; + } else { + // + // Translate '\r' to '\r' + // + ArgumentString =3D "\r"; + Format -=3D BytesPerFormatCharacter; + } + break; + + case '\n': + // + // Translate '\n' to '\r\n' and '\n\r' to '\r\n' + // + ArgumentString =3D "\r\n"; + Format +=3D BytesPerFormatCharacter; + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) & Fo= rmatMask; + if (FormatCharacter !=3D '\r') { + Format -=3D BytesPerFormatCharacter; + } + break; + + case '%': + default: + // + // if the type is '%' or unknown, then print it to the screen + // + ArgumentString =3D (CHAR8 *)&FormatCharacter; + Flags |=3D ARGUMENT_UNICODE; + break; + } + break; + + case '\r': + Format +=3D BytesPerFormatCharacter; + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) & Form= atMask; + if (FormatCharacter =3D=3D '\n') { + // + // Translate '\r\n' to '\r\n' + // + ArgumentString =3D "\r\n"; + } else { + // + // Translate '\r' to '\r' + // + ArgumentString =3D "\r"; + Format -=3D BytesPerFormatCharacter; + } + break; + + case '\n': + // + // Translate '\n' to '\r\n' and '\n\r' to '\r\n' + // + ArgumentString =3D "\r\n"; + Format +=3D BytesPerFormatCharacter; + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) & Form= atMask; + if (FormatCharacter !=3D '\r') { + Format -=3D BytesPerFormatCharacter; + } + break; + + default: + ArgumentString =3D (CHAR8 *)&FormatCharacter; + Flags |=3D ARGUMENT_UNICODE; + break; + } + + // + // Retrieve the ArgumentString attriubutes + // + if ((Flags & ARGUMENT_UNICODE) !=3D 0) { + ArgumentMask =3D 0xffff; + BytesPerArgumentCharacter =3D 2; + } else { + ArgumentMask =3D 0xff; + BytesPerArgumentCharacter =3D 1; + } + if ((Flags & ARGUMENT_REVERSED) !=3D 0) { + BytesPerArgumentCharacter =3D -BytesPerArgumentCharacter; + } else { + // + // Compute the number of characters in ArgumentString and store it i= n Count + // ArgumentString is either null-terminated, or it contains Precisio= n characters + // + for (Count =3D 0; Count < Precision || ((Flags & PRECISION) =3D=3D 0= ); Count++) { + ArgumentCharacter =3D ((ArgumentString[Count * BytesPerArgumentCha= racter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) = << 8)) & ArgumentMask; + if (ArgumentCharacter =3D=3D 0) { + break; + } + } + } + + if (Precision < Count) { + Precision =3D Count; + } + + // + // Pad before the string + // + if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) =3D=3D (PAD_TO_WIDTH)) { + LengthToReturn +=3D ((Width - Precision) * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Prec= ision, ' ', BytesPerOutputCharacter); + } + } + + if (ZeroPad) { + if (Prefix !=3D 0) { + LengthToReturn +=3D (1 * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix,= BytesPerOutputCharacter); + } + } + LengthToReturn +=3D ((Precision - Count) * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - = Count, '0', BytesPerOutputCharacter); + } + } else { + LengthToReturn +=3D ((Precision - Count) * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - = Count, ' ', BytesPerOutputCharacter); + } + if (Prefix !=3D 0) { + LengthToReturn +=3D (1 * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix,= BytesPerOutputCharacter); + } + } + } + + // + // Output the Prefix character if it is present + // + Index =3D 0; + if (Prefix !=3D 0) { + Index++; + } + + // + // Copy the string into the output buffer performing the required type= conversions + // + while (Index < Count) { + ArgumentCharacter =3D ((*ArgumentString & 0xff) | (*(ArgumentString = + 1) << 8)) & ArgumentMask; + + LengthToReturn +=3D (1 * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentC= haracter, BytesPerOutputCharacter); + } + ArgumentString +=3D BytesPerArgumentCharacter; + Index++; + if (Comma) { + Digits++; + if (Digits =3D=3D 3) { + Digits =3D 0; + Index++; + if (Index < Count) { + LengthToReturn +=3D (1 * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL= ) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ','= , BytesPerOutputCharacter); + } + } + } + } + } + + // + // Pad after the string + // + if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) =3D=3D (PAD_TO_WIDTH | LEF= T_JUSTIFY)) { + LengthToReturn +=3D ((Width - Precision) * BytesPerOutputCharacter); + if ((Flags & COUNT_ONLY_NO_PRINT) =3D=3D 0 && Buffer !=3D NULL) { + Buffer =3D BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Prec= ision, ' ', BytesPerOutputCharacter); + } + } + + // + // Get the next character from the format string + // + Format +=3D BytesPerFormatCharacter; + + // + // Get the next character from the format string + // + FormatCharacter =3D ((*Format & 0xff) | (*(Format + 1) << 8)) & Format= Mask; + } + + if ((Flags & COUNT_ONLY_NO_PRINT) !=3D 0) { + return (LengthToReturn / BytesPerOutputCharacter); + } + + ASSERT (Buffer !=3D NULL); + // + // Null terminate the Unicode or ASCII string + // + BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, = 0, BytesPerOutputCharacter); + // + // Make sure output buffer cannot contain more than PcdMaximumUnicodeStr= ingLength + // Unicode characters if PcdMaximumUnicodeStringLength is not zero. + // + ASSERT ((((Flags & OUTPUT_UNICODE) =3D=3D 0)) || (FceStrSize ((CHAR16 *)= OriginalBuffer) !=3D 0)); + // + // Make sure output buffer cannot contain more than PcdMaximumAsciiStrin= gLength + // ASCII characters if PcdMaximumAsciiStringLength is not zero. + // + ASSERT ((((Flags & OUTPUT_UNICODE) !=3D 0)) || ((strlen (OriginalBuffer)= + 1) !=3D 0)); + + return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter); +} + +/** + Worker function that produces a Null-terminated string in an output buff= er + based on a Null-terminated format string and variable argument list. + + VSPrint function to process format and place the results in Buffer. Sinc= e 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 p= arsing + of Format into. + @param BufferSize The maximum number of characters to put into buffe= r. + 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, Forma= tString, 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 return= ed not including + the Null-terminator. + If BufferSize is 0 or 1, then no output buffer is produced and 0 is retu= rned. + + 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-terminat= ed 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 specifi= ed 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 n= ot 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 conten= ts of the format string. + The number of Unicode characters in the produced output buffer is return= ed not including + the Null-terminator. + If BufferSize is 0 or 1, then no output buffer is produced and 0 is retu= rned. + + 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-terminat= ed 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 specifi= ed by StartOfBuffer. + @param FormatString A Null-terminated Unicode format string. + @param ... Variable argument list whose contents are access= ed based on the + format string specified by FormatString. + + @return The number of Unicode characters in the produced output buffer n= ot 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 =3D Destination; + assert (Destination !=3D NULL); + assert (Source !=3D NULL); + assert (((UINTN) Source & 0x01) =3D=3D 0); + + while (*Source !=3D L'\0') { + // + // If any Unicode characters in Source contain + // non-zero value in the upper 8 bits, then ASSERT(). + // + assert (*Source < 0x100); + *(ReturnValue++) =3D (CHAR8) *(Source++); + } + + *ReturnValue =3D '\0'; + + return Destination; +} + +/** + Allocate new memory and then copy the Unicode string Source to Destinati= on. + + @param Dest Location to copy string + @param Src String to copy + +**/ +VOID +NewStringCpy ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + if (*Dest !=3D NULL) { + FreePool (*Dest); + } + *Dest =3D FceAllocateCopyPool (FceStrSize (Src), Src); + ASSERT (*Dest !=3D 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 >=3D L'0') && (Char <=3D 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 >=3D L'a') && (Char <=3D 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 >=3D L'A') && (Char <=3D L'F')) || + ((Char >=3D L'a') && (Char <=3D 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) !=3D 0); + + // + // Ignore the pad spaces (space or tab) + // + while ((*String =3D=3D L' ') || (*String =3D=3D L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String =3D=3D L'0') { + String++; + } + + Result =3D 0; + + while (FceInternalIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according + // to the range defined by UINTN, then ASSERT(). + // + ASSERT (Result <=3D DivU64x32 (((UINT64) ~0) - (*String - L'0') , 10)); + + Result =3D 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 on= e 0. + The function will ignore the pad space, which includes spaces or tab cha= racters, + 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 cha= racter 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 def= ined by + UINT64, then ASSERT(). + + If PcdMaximumUnicodeStringLength is not zero, and String contains more t= han + 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) !=3D 0); + + // + // Ignore the pad spaces (space or tab) + // + while ((*String =3D=3D L' ') || (*String =3D=3D L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String =3D=3D L'0') { + String++; + } + + if (FceInternalCharToUpper (*String) =3D=3D L'X') { + ASSERT (*(String - 1) =3D=3D L'0'); + if (*(String - 1) !=3D L'0') { + return 0; + } + // + // Skip the 'X' + // + String++; + } + + Result =3D 0; + + while (FceInternalIsHexaDecimalDigitCharacter (*String)) { + // + // If the Hex Number represented by String overflows according + // to the range defined by UINTN, then ASSERT(). + // + ASSERT (Result <=3D RShiftU64 (((UINT64) ~0) - FceInternalHexCharToUin= tn (*String) , 4)); + + Result =3D LShiftU64 (Result, 4); + Result =3D Result + FceInternalHexCharToUintn (*String); + String++; + } + + return Result; +} + + +CHAR16 +ToUpper ( + CHAR16 a + ) +{ + if (('a' <=3D a) && (a <=3D 'z')) { + return (CHAR16) (a - 0x20); + } else { + return a; + } +} + +CHAR16 +ToLower ( + CHAR16 a + ) +{ + if (('A' <=3D a) && (a <=3D '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 !=3D NULL); + assert (Pattern !=3D NULL); + + for (;;) { + p =3D *Pattern; + Pattern +=3D 1; + + if (p =3D=3D 0) { + // + // End of pattern. If end of string, TRUE match + // + if (*String) { + return FALSE; + } else { + return TRUE; + } + + } else { + + c =3D *String; + if (ToUpper (c) !=3D ToUpper (p)) { + return FALSE; + } + + String +=3D 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 3= 2-bit + unsigned value Multiplier and generates a 64-bit unsigned result. This 6= 4- + 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 gener= ates + 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 !=3D 0); + return Dividend / Divisor; +} + +/** + Shifts a 64-bit integer left between 0 and 63 bits. The low bits are fil= led + 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 gener= ates + 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 Rema= inder + 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 !=3D 0); + + if (Remainder !=3D NULL) { + *Remainder =3D (UINT32)(Dividend % Divisor); + } + return Dividend / Divisor; +} + +/** + Copies a buffer to an allocated buffer. + + Allocates the number bytes specified by AllocationSize, copies allocatio= nSize 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 return= ed. If there + is not enough memory remaining to satisfy the request, then NULL is retu= rned. + + 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 =3D NULL; + + if ((Buffer =3D=3D NULL) || (AllocationSize =3D=3D 0)) { + return Memory; + } + + Memory =3D calloc (AllocationSize, sizeof (CHAR8)); + if (Memory !=3D NULL) { + Memory =3D memcpy (Memory, Buffer, AllocationSize); + } + return Memory; +} + +/** + Initializes the head node of a doubly-linked list, and returns the point= er 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 i= s 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 !=3D NULL); + + ListHead->ForwardLink =3D ListHead; + ListHead->BackLink =3D ListHead; + return ListHead; +} + +/** + Adds a node to the beginning of a doubly-linked list, and returns the po= inter + 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 num= ber + 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 begi= nning + of a doubly-linked list. + + @return ListHead + +**/ +LIST_ENTRY * +InsertHeadList ( + IN OUT LIST_ENTRY *ListHead, + IN OUT LIST_ENTRY *Entry + ) +{ + assert ((ListHead !=3D NULL) && (Entry !=3D NULL)); + + Entry->ForwardLink =3D ListHead->ForwardLink; + Entry->BackLink =3D ListHead; + Entry->ForwardLink->BackLink =3D Entry; + ListHead->ForwardLink =3D 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 List= Head, + 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 num= ber + 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 !=3D NULL) && (Entry !=3D NULL)); + + Entry->ForwardLink =3D ListHead; + Entry->BackLink =3D ListHead->BackLink; + Entry->BackLink->ForwardLink =3D Entry; + ListHead->BackLink =3D 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 !=3D 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 ASSE= RT(). + + @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 retu= rned. + +**/ +LIST_ENTRY * +GetNextNode ( + IN CONST LIST_ENTRY *List, + IN CONST LIST_ENTRY *Node + ) +{ + assert ((List !=3D NULL) && (Node !=3D 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 ASSE= RT(). + + @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 !=3D NULL) && (Node !=3D 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 con= tains + 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 !=3D NULL); + + return (BOOLEAN)(ListHead->ForwardLink =3D=3D ListHead); +} + +/** + Determines if a node in a doubly-linked list is the head node of a the s= ame + 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 n= ode. + + 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 Initi= alizeListHead(), + 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 i= s 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 !=3D NULL) && (Node !=3D NULL)); + + return (BOOLEAN)(Node =3D=3D 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 specifie= d 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 ASSE= RT(). + + @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 !=3D NULL) && (Node !=3D NULL)); + + return (BOOLEAN)(!IsNull (List, Node) && (List->BackLink =3D=3D Node)); +} + +/** + Removes a node from a doubly-linked list, and returns the node that foll= ows + 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 require= d. 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 lin= ked + 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 =3D Entry->BackLink; + Entry->BackLink->ForwardLink =3D Entry->ForwardLink; + return Entry->ForwardLink; +} + diff --git a/Platform/Intel/Tools/FCE/Common.h b/Platform/Intel/Tools/FCE/C= ommon.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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef _COMMON_LIB_H_ +#define _COMMON_LIB_H_ + +#include +#include +#include +#ifdef __GNUC__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include "CommonLib.h" +#include + +#define MAX_QUI_PARAM_LEN 2000 +#define ERROR_INFO_LENGTH 400 +#define MAX_STR_LEN_FOR_PICK_UQI 200 +#define MAX_PLATFORM_DEFAULT_ID_NUM 1000 +#define _MAX_BUILD_VERSION 100 +#define _MAXIMUM_SECTION_FILE_NUM 1000 + +#ifndef _MAX_PATH +#define _MAX_PATH 500 +#endif + +/// +/// Variable attributes. +/// +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 + +/// +/// This attribute is identified by the mnemonic 'HR' +/// elsewhere in this specification. +/// +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 + +#define VARSTORE_LIST_TYPE 0x0000000000000001ULL +#define EFI_VARSTORE_LIST_TYPE 0x0000000000000002ULL +#define PLATFORM_DEFAULT_ID_TYPE 0x0000000000000004ULL +#define UQI_LIST_TYPE 0x0000000000000008ULL +#define HII_OBJ_LIST_TYPE 0x0000000000000010ULL + +/// +/// LIST_ENTRY structure definition. +/// +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *ForwardLink; + struct _LIST_ENTRY *BackLink; +} LIST_ENTRY; + +#define CR(Record, TYPE, Field, TestSignature) ((TYPE *) ((CHAR8 *) (Reco= rd) - (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 sp= ecified + 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 s= pecified + 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) = =3D=3D 0) + +/** + Returns an argument of a specified type from a variable argument list an= d 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 updat= ed to point + to the next argument in the variable argument list. The method for comp= uting the + pointer to the next argument in the argument list is CPU specific follow= ing the EFIAPI ABI. + + @param Marker The pointer to the beginning of a variable argument li= st. + @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 +=3D _BASE_INT_SIZE_O= F (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 =3D 28 +/// "-9,223,372,036,854,775,808" +/// Maximum Length Hexadecimal String =3D 17 +/// "FFFFFFFFFFFFFFFF" +/// Maximum Length GUID =3D 37 +/// "00000000-0000-0000-0000-000000000000" +/// Maximum Length TIME =3D 18 +/// "12/12/2006 12:12" +/// +#define MAXIMUM_VALUE_CHARACTERS 38 + +/// +/// Pointer to the start of a variable argument list stored in a memory bu= ffer. 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 neare= st UINTN boundary. +**/ +#define _BASE_INT_SIZE_OF(TYPE) ((sizeof (TYPE) + sizeof (UINTN) - 1) / si= zeof (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 Uni= code + string and returns the new Unicode string. + + This function copies the contents of the Unicode string Source to the Un= icode + 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-termi= nated + 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 t= han + 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 f= irst + 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-terminat= ed + Unicode string, and returns the concatenated Unicode string. + + This function concatenates two Null-terminated Unicode strings. The cont= ents + of Null-terminated Unicode string Source are concatenated to the end of + Null-terminated Unicode string Destination. The Null-terminated concaten= ated + 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 m= ore + than PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and Source contains more t= han + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and concatenating Destinat= ion + 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 Un= icode + string Destination, and returns Destination. The function terminates the + Unicode string Destination by appending a Null-terminator character at t= he end. + The caller is responsible to make sure Destination points to a buffer wi= th 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 buff= er + based on a Null-terminated format string and variable argument list. + + VSPrint function to process format and place the results in Buffer. Sinc= e 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 p= arsing + of Format into. + @param BufferSize The maximum number of characters to put into buffe= r. + 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 conten= ts of the format string. + The number of Unicode characters in the produced output buffer is return= ed not including + the Null-terminator. + If BufferSize is 0 or 1, then no output buffer is produced and 0 is retu= rned. + + 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-terminat= ed 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 specifi= ed by StartOfBuffer. + @param FormatString A Null-terminated Unicode format string. + @param ... Variable argument list whose contents are access= ed based on the + format string specified by FormatString. + + @return The number of Unicode characters in the produced output buffer n= ot 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 Destinati= on. + + @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 on= e 0. + The function will ignore the pad space, which includes spaces or tab cha= racters, + 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 cha= racter 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 def= ined by + UINT64, then ASSERT(). + + If PcdMaximumUnicodeStringLength is not zero, and String contains more t= han + 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 3= 2-bit + unsigned value Multiplier and generates a 64-bit unsigned result. This 6= 4- + 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 gener= ates + 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 fil= led + 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 gener= ates + 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 Rema= inder + 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 allocatio= nSize 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 return= ed. If there + is not enough memory remaining to satisfy the request, then NULL is retu= rned. + + 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 point= er 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 i= s 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 po= inter + 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 num= ber + 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 begi= nning + 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 List= Head, + 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 num= ber + 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 ASSE= RT(). + + @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 retu= rned. + +**/ +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 ASSE= RT(). + + @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 con= tains + 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 s= ame + 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 n= ode. + + 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 Initi= alizeListHead(), + 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 i= s 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 specifie= d 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 ASSE= RT(). + + @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 foll= ows + 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 require= d. 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 lin= ked + 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/F= CE/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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "IfrParse.h" + +#define gEmptyString L"" +// +// Global stack used to evaluate boolean expresions +// +EFI_HII_VALUE *mOpCodeScopeStack =3D NULL; +EFI_HII_VALUE *mOpCodeScopeStackEnd =3D NULL; +EFI_HII_VALUE *mOpCodeScopeStackPointer =3D NULL; + +EFI_HII_VALUE *mExpressionEvaluationStack =3D NULL; +EFI_HII_VALUE *mExpressionEvaluationStackEnd =3D NULL; +EFI_HII_VALUE *mExpressionEvaluationStackPointer =3D NULL; +UINTN mExpressionEvaluationStackOffset =3D 0; + +EFI_HII_VALUE *mCurrentExpressionStack =3D NULL; +EFI_HII_VALUE *mCurrentExpressionEnd =3D NULL; +EFI_HII_VALUE *mCurrentExpressionPointer =3D NULL; + +EFI_HII_VALUE *mMapExpressionListStack =3D NULL; +EFI_HII_VALUE *mMapExpressionListEnd =3D NULL; +EFI_HII_VALUE *mMapExpressionListPointer =3D 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 =3D NULL; + + Link =3D GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node =3D NAME_VALUE_NODE_FROM_LINK (Link); + + if (FceStrCmp (Name, Node->Name) =3D=3D 0) { + NewStringCpy (Value, Node->EditValue); + return EFI_SUCCESS; + } + + Link =3D 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: n= ew stack + pointer + @param StackEnd On input: old stack end; On output: new s= tack 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 =3D EXPRESSION_STACK_SIZE_INCREMENT; + if (*StackPtr !=3D NULL) { + Size =3D Size + (*StackEnd - *Stack); + } + + NewStack =3D AllocatePool (Size * sizeof (EFI_HII_VALUE)); + if (NewStack =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (*StackPtr !=3D 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 =3D NewStack + (*StackPtr - *Stack); + *Stack =3D NewStack; + *StackEnd =3D 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: n= ew stack + pointer + @param StackEnd On input: old stack end; On output: new s= tack 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 >=3D *StackEnd) { + // + // Grow the stack + // + Status =3D GrowStack (Stack, StackPtr, StackEnd); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Push the item onto the stack + // + CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE)); + *StackPtr =3D *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: n= ew 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 =3D=3D Stack) { + return EFI_ACCESS_DENIED; + } + + // + // Pop the item off the stack + // + *StackPtr =3D *StackPtr - 1; + CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; +} + + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetCurrentExpressionStack ( + VOID + ) +{ + mCurrentExpressionPointer =3D 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 =3D EFI_IFR_TYPE_NUM_SIZE_64; + Data.Value.u64 =3D (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 =3D PopStack ( + mCurrentExpressionStack, + &mCurrentExpressionPointer, + &Data + ); + + *Pointer =3D (VOID *) (UINTN) Data.Value.u64; + + return Status; +} + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetMapExpressionListStack ( + VOID + ) +{ + mMapExpressionListPointer =3D 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 =3D EFI_IFR_TYPE_NUM_SIZE_64; + Data.Value.u64 =3D (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 =3D PopStack ( + mMapExpressionListStack, + &mMapExpressionListPointer, + &Data + ); + + *Pointer =3D (VOID *) (UINTN) Data.Value.u64; + + return Status; +} + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetScopeStack ( + VOID + ) +{ + mOpCodeScopeStackPointer =3D 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 =3D EFI_IFR_TYPE_NUM_SIZE_8; + Data.Value.u8 =3D 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 =3D PopStack ( + mOpCodeScopeStack, + &mOpCodeScopeStackPointer, + &Data + ); + + *Operand =3D 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 =3D mExpressionEvaluationStackOffset; + mExpressionEvaluationStackOffset =3D mExpressionEvaluationStackPointer -= mExpressionEvaluationStack; + return TempStackOffset; +} + +/** + Restore stack offset based on input stack offset + + @param StackOffset Offset to stack start. + +**/ +VOID +RestoreExpressionEvaluationStackOffset ( + UINTN StackOffset + ) +{ + mExpressionEvaluationStackOffset =3D 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 =3D=3D 0) { + // + // The value of zero is reserved + // + return NULL; + } + + Link =3D GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question =3D FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Question->QuestionId =3D=3D QuestionId) { + return Question; + } + + Link =3D 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 =3D IdToQuestion2 (Form, QuestionId); + if (Question !=3D NULL) { + return Question; + } + + // + // Search in the formset scope + // + Link =3D GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form =3D FORM_BROWSER_FORM_FROM_LINK (Link); + + Question =3D IdToQuestion2 (Form, QuestionId); + if (Question !=3D NULL) { + return Question; + } + + Link =3D 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 for= m. + +**/ +FORM_EXPRESSION * +RuleIdToExpression ( + IN FORM_BROWSER_FORM *Form, + IN UINT8 RuleId + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link =3D GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression =3D FORM_EXPRESSION_FROM_LINK (Link); + + if ((Expression->Type =3D=3D EFI_HII_EXPRESSION_RULE) && (Expression->= RuleId =3D=3D RuleId)) { + return Expression; + } + + Link =3D 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 !=3D 0) { + if ((*String >=3D 'a') && (*String <=3D 'z')) { + *String =3D (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 =3D 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 =3D MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16); + switch (Format) { + case EFI_IFR_STRING_UNSIGNED_DEC: + case EFI_IFR_STRING_SIGNED_DEC: + PrintFormat =3D L"%ld"; + break; + + case EFI_IFR_STRING_LOWERCASE_HEX: + PrintFormat =3D L"%lx"; + break; + + case EFI_IFR_STRING_UPPERCASE_HEX: + PrintFormat =3D 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 =3D EFI_IFR_TYPE_STRING; + //Result->Value.string =3D 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 =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value.Type >=3D EFI_IFR_TYPE_OTHER) { + return EFI_UNSUPPORTED; + } + + Status =3D EFI_SUCCESS; + if (Value.Type =3D=3D EFI_IFR_TYPE_STRING) { + String =3D GetToken (Value.Value.string, FormSet->UnicodeBinary); + if (String =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + IfrStrToUpper (String); + StringPtr =3D StrStr (String, L"0X"); + if (StringPtr !=3D NULL) { + // + // Hex string + // + Result->Value.u64 =3D FceStrHexToUint64 (String); + } else { + // + // decimal string + // + Result->Value.u64 =3D FceStrDecimalToUint64 (String); + } + FreePool (String); + } else { + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + } + + Result->Type =3D 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] =3D NULL; + String[1] =3D NULL; + StringPtr =3D NULL; + Status =3D EFI_SUCCESS; + + for (Index =3D 0; Index < 2; Index++) { + Status =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type !=3D EFI_IFR_TYPE_STRING) { + Status =3D EFI_UNSUPPORTED; + goto Done; + } + + String[Index] =3D GetToken (Value.Value.string, FormSet->UnicodeBinary= ); + if (String[Index] =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + } + + Size =3D FceStrSize (String[0]); + StringPtr=3D AllocatePool (FceStrSize (String[1]) + Size); + ASSERT (StringPtr !=3D NULL); + StrCpy (StringPtr, String[1]); + StrCat (StringPtr, String[0]); + + Result->Type =3D EFI_IFR_TYPE_STRING; + //Result->Value.string =3D NewString (StringPtr, FormSet->HiiHandle); + +Done: + if (String[0] !=3D NULL) { + FreePool (String[0]); + } + if (String[1] !=3D NULL) { + FreePool (String[1]); + } + if (StringPtr !=3D 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] =3D NULL; + String[1] =3D NULL; + Status =3D EFI_SUCCESS; + for (Index =3D 0; Index < 2; Index++) { + Status =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type !=3D EFI_IFR_TYPE_STRING) { + Status =3D EFI_UNSUPPORTED; + goto Done; + } + + String[Index] =3D GetToken (Value.Value.string, FormSet->UnicodeBinary= ); + if (String [Index] =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + } + + Result->Type =3D EFI_IFR_TYPE_BOOLEAN; + Result->Value.b =3D MetaiMatch (String[0], String[1]); + +Done: + if (String[0] !=3D NULL) { + FreePool (String[0]); + } + if (String[1] !=3D 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 =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base =3D (UINTN) Value.Value.u64; + + // + // String[0] - sub-string + // String[1] - The string to search + // + String[0] =3D NULL; + String[1] =3D NULL; + for (Index =3D 0; Index < 2; Index++) { + Status =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type !=3D EFI_IFR_TYPE_STRING) { + Status =3D EFI_UNSUPPORTED; + goto Done; + } + + String[Index] =3D GetToken (Value.Value.string, FormSet->UnicodeBinary= ); + if (String[Index] =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + + if (Format =3D=3D EFI_IFR_FF_CASE_INSENSITIVE) { + // + // Case insensitive, convert both string to upper case + // + IfrStrToUpper (String[Index]); + } + } + + Result->Type =3D EFI_IFR_TYPE_NUM_SIZE_64; + if (Base >=3D FceStrLen (String[1])) { + Result->Value.u64 =3D 0xFFFFFFFFFFFFFFFFULL; + } else { + StringPtr =3D StrStr (String[1] + Base, String[0]); + Result->Value.u64 =3D (StringPtr =3D=3D NULL) ? 0xFFFFFFFFFFFFFFFFULL = : (StringPtr - String[1]); + } + +Done: + if (String[0] !=3D NULL) { + FreePool (String[0]); + } + if (String[1] !=3D 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 =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Length =3D (UINTN) Value.Value.u64; + + Status =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base =3D (UINTN) Value.Value.u64; + + Status =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type !=3D EFI_IFR_TYPE_STRING) { + return EFI_UNSUPPORTED; + } + String =3D GetToken (Value.Value.string, FormSet->UnicodeBinary); + if (String =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + if ((Length =3D=3D 0) || (Base >=3D FceStrLen (String))) { + SubString =3D gEmptyString; + } else { + SubString =3D String + Base; + if ((Base + Length) < FceStrLen (String)) { + SubString[Length] =3D L'\0'; + } + } + + Result->Type =3D EFI_IFR_TYPE_STRING; + //Result->Value.string =3D 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 =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Count =3D (UINTN) Value.Value.u64; + + // + // String[0] - Delimiter + // String[1] - The string to search + // + String[0] =3D NULL; + String[1] =3D NULL; + for (Index =3D 0; Index < 2; Index++) { + Status =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type !=3D EFI_IFR_TYPE_STRING) { + Status =3D EFI_UNSUPPORTED; + goto Done; + } + + String[Index] =3D GetToken (Value.Value.string, FormSet->UnicodeBinary= ); + if (String[Index] =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + } + + Delimiter =3D String[0]; + SubString =3D String[1]; + while (Count > 0) { + SubString =3D StrStr (SubString, Delimiter); + if (SubString !=3D NULL) { + // + // Skip over the delimiter + // + SubString =3D SubString + FceStrLen (Delimiter); + } else { + break; + } + Count--; + } + + if (SubString =3D=3D NULL) { + // + // nth delimited sub-string not found, push an empty string + // + SubString =3D gEmptyString; + } else { + // + // Put a NULL terminator for nth delimited sub-string + // + StringPtr =3D StrStr (SubString, Delimiter); + if (StringPtr !=3D NULL) { + *StringPtr =3D L'\0'; + } + } + + Result->Type =3D EFI_IFR_TYPE_STRING; + //Result->Value.string =3D NewString (SubString, FormSet->HiiHandle); + +Done: + if (String[0] !=3D NULL) { + FreePool (String[0]); + } + if (String[1] !=3D 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 =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base =3D (UINTN) Value.Value.u64; + + // + // String[0] - Charset + // String[1] - The string to search + // + String[0] =3D NULL; + String[1] =3D NULL; + for (Index =3D 0; Index < 2; Index++) { + Status =3D PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type !=3D EFI_IFR_TYPE_STRING) { + Status =3D EFI_UNSUPPORTED; + goto Done; + } + + String[Index] =3D GetToken (Value.Value.string, FormSet->UnicodeBinary= ); + if (String [Index] =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + } + + if (Base >=3D FceStrLen (String[1])) { + Status =3D EFI_UNSUPPORTED; + goto Done; + } + + Found =3D FALSE; + StringPtr =3D String[1] + Base; + Charset =3D String[0]; + while (*StringPtr !=3D 0 && !Found) { + Index =3D 0; + while (Charset[Index] !=3D 0) { + if ((*StringPtr >=3D Charset[Index]) && (*StringPtr <=3D Charset[Ind= ex + 1])) { + if (Flags =3D=3D EFI_IFR_FLAGS_FIRST_MATCHING) { + Found =3D TRUE; + break; + } + } else { + if (Flags =3D=3D EFI_IFR_FLAGS_FIRST_NON_MATCHING) { + Found =3D TRUE; + break; + } + } + // + // Skip characters pair representing low-end of a range and high-end= of a range + // + Index +=3D 2; + } + + if (!Found) { + StringPtr++; + } + } + + Result->Type =3D EFI_IFR_TYPE_NUM_SIZE_64; + Result->Value.u64 =3D StringPtr - String[1]; + +Done: + if (String[0] !=3D NULL) { + FreePool (String[0]); + } + if (String[1] !=3D 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 =3D 0; + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Temp =3D Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Temp =3D Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Temp =3D Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + Temp =3D Value->Value.b; + break; + + case EFI_IFR_TYPE_TIME: + Temp =3D Value->Value.u32 & 0xffffff; + break; + + case EFI_IFR_TYPE_DATE: + Temp =3D Value->Value.u32; + break; + + default: + return; + } + + Value->Value.u64 =3D 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 >=3D EFI_IFR_TYPE_OTHER) || (Value2->Type >=3D EFI_IFR= _TYPE_OTHER) ) { + return EFI_INVALID_PARAMETER; + } + + if ((Value1->Type =3D=3D EFI_IFR_TYPE_STRING) || (Value2->Type =3D=3D EF= I_IFR_TYPE_STRING) ) { + if (Value1->Type !=3D Value2->Type) { + // + // Both Operator should be type of String + // + return EFI_INVALID_PARAMETER; + } + + if ((Value1->Value.string =3D=3D 0) || (Value2->Value.string =3D=3D 0)= ) { + // + // StringId 0 is reserved + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string =3D=3D Value2->Value.string) { + return 0; + } + + Str1 =3D GetToken (Value1->Value.string, FormSet->UnicodeBinary); + if (Str1 =3D=3D NULL) { + // + // String not found + // + return EFI_INVALID_PARAMETER; + } + + Str2 =3D GetToken (Value2->Value.string, FormSet->UnicodeBinary); + if (Str2 =3D=3D NULL) { + FreePool (Str1); + return EFI_INVALID_PARAMETER; + } + + Result =3D FceStrCmp (Str1, Str2); + + FreePool (Str1); + FreePool (Str2); + + return Result; + } + + // + // Take remain types(integer, boolean, date/time) as integer + // + Temp64 =3D (INT64) (Value1->Value.u64 - Value2->Value.u64); + if (Temp64 > 0) { + Result =3D 1; + } else if (Temp64 < 0) { + Result =3D -1; + } else { + Result =3D 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 =3D=3D EFI_IFR_EQ_ID_VAL_OP) || + (Operand =3D=3D EFI_IFR_EQ_ID_ID_OP) || + (Operand =3D=3D EFI_IFR_EQ_ID_VAL_LIST_OP )|| + (Operand =3D=3D EFI_IFR_QUESTION_REF1_OP) || + (Operand =3D=3D EFI_IFR_QUESTION_REF2_OP) || + (Operand =3D=3D EFI_IFR_QUESTION_REF3_OP) || + (Operand =3D=3D EFI_IFR_THIS_OP ) || + (Operand =3D=3D EFI_IFR_SECURITY_OP) || + (Operand =3D=3D EFI_IFR_GET_OP) || + (Operand =3D=3D 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 =3D EFI_SUCCESS; + HiiValue =3D &Question->HiiValue; + + Status =3D 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 expre= ssion. If constant, will return TRUE. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a Questi= onId + 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 =3D SaveExpressionEvaluationStackOffset (); + + ASSERT (Expression !=3D NULL); + Expression->Result.Type =3D EFI_IFR_TYPE_OTHER; + + Link =3D GetFirstNode (&Expression->OpCodeListHead); + while (!IsNull (&Expression->OpCodeListHead, Link)) { + OpCode =3D EXPRESSION_OPCODE_FROM_LINK (Link); + + Link =3D GetNextNode (&Expression->OpCodeListHead, Link); + + ZeroMem (&Data1, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data2, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data3, sizeof (EFI_HII_VALUE)); + + Value =3D &Data3; + Value->Type =3D EFI_IFR_TYPE_BOOLEAN; + Status =3D EFI_SUCCESS; + + // + // Check whether it is a constant expression or not + // + if (*ConstantExpression) { + *ConstantExpression =3D IsConstantExpressionOpCode (OpCode->Operand); + } + + switch (OpCode->Operand) { + // + // Built-in functions + // + case EFI_IFR_EQ_ID_VAL_OP: + Question =3D IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + UpdateHiiValue (FormSet, Question); + Result =3D CompareHiiValue (&Question->HiiValue, &OpCode->Value, For= mSet); + if ((EFI_STATUS)Result =3D=3D EFI_INVALID_PARAMETER) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + Value->Value.b =3D (BOOLEAN) ((Result =3D=3D 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_ID_OP: + Question =3D IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + + Question2 =3D IdToQuestion (FormSet, Form, OpCode->QuestionId2); + if (Question2 =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + UpdateHiiValue (FormSet, Question); + UpdateHiiValue (FormSet, Question2); + Result =3D CompareHiiValue (&Question->HiiValue, &Question2->HiiValu= e, FormSet); + if ((EFI_STATUS)Result =3D=3D EFI_INVALID_PARAMETER) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + Value->Value.b =3D (BOOLEAN) ((Result =3D=3D 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_VAL_LIST_OP: + + Question =3D IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + UpdateHiiValue (FormSet, Question); + Value->Value.b =3D FALSE; + for (Index =3D0; Index < OpCode->ListLength; Index++) { + if (Question->HiiValue.Value.u16 =3D=3D OpCode->ValueList[Index]) { + Value->Value.b =3D TRUE; + break; + } + } + break; + + case EFI_IFR_DUP_OP: + Status =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status =3D PushExpression (Value); + break; + + case EFI_IFR_QUESTION_REF1_OP: + case EFI_IFR_THIS_OP: + Question =3D IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + UpdateHiiValue (FormSet, Question); + Value =3D &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 =3D EFI_IFR_TYPE_UNDEFINED; + Value->Value.u8 =3D 0; + if (OpCode->VarStorage !=3D NULL) { + switch (OpCode->VarStorage->Type) { + case EFI_IFR_VARSTORE_OP: + // + // Get value from Buffer + // + Value->Type =3D OpCode->ValueType; + CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->Var= StoreInfo.VarOffset, OpCode->ValueWidth); + break; + + case EFI_IFR_VARSTORE_EFI_OP: + // + // Get value from Buffer + // + if (OpCode->VarStorage->NewEfiVarstore) { + Value->Type =3D OpCode->ValueType; + CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->V= arStoreInfo.VarOffset, OpCode->ValueWidth); + } else { + CopyMem (&Value->Value, OpCode->VarStorage->Buffer, OpCode->ValueW= idth); + } + + + break; + case EFI_HII_VARSTORE_NAME_VALUE: + if (OpCode->ValueType !=3D EFI_IFR_TYPE_STRING) { + // + // Get value from string except for STRING value. + // + Status =3D GetValueByName (OpCode->VarStorage, OpCode->ValueNa= me, &StrPtr); + if (!EFI_ERROR (Status)) { + ASSERT (StrPtr !=3D NULL); + TempLength =3D FceStrLen (StrPtr); + if (OpCode->ValueWidth >=3D ((TempLength + 1) / 2)) { + Value->Type =3D OpCode->ValueType; + TempBuffer =3D (UINT8 *) &Value->Value; + ZeroMem (TempStr, sizeof (TempStr)); + for (Index =3D 0; Index < TempLength; Index ++) { + TempStr[0] =3D StrPtr[TempLength - Index - 1]; + DigitUint8 =3D (UINT8) FceStrHexToUint64 (TempStr); + if ((Index & 1) =3D=3D 0) { + TempBuffer [Index/2] =3D DigitUint8; + } else { + TempBuffer [Index/2] =3D (UINT8) ((DigitUint8 << 4) + = TempBuffer [Index/2]); + } + } + } + free (StrPtr); + StrPtr =3D NULL; + } + } + break; + default: + // + // Not recognize storage. + // + Status =3D EFI_UNSUPPORTED; + goto Done; + } + } + + break; + + case EFI_IFR_QUESTION_REF3_OP: + if (OpCode->DevicePath =3D=3D 0) { + // + // EFI_IFR_QUESTION_REF3 + // Pop an expression from the expression stack + // + Status =3D 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 =3D EFI_NOT_FOUND; + goto Done; + } + + Question =3D IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + + // + // push the questions' value on to the expression stack + // + Value =3D &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 =3D RuleIdToExpression (Form, OpCode->RuleId); + if (RuleExpression =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + + // + // Evaluate this rule expression + // + Status =3D EvaluateExpression (FormSet, Form, RuleExpression, Consta= ntExpression); + if (EFI_ERROR (Status)) { + goto Done; + } + + Value =3D &RuleExpression->Result; + break; + + case EFI_IFR_STRING_REF1_OP: + Value->Type =3D EFI_IFR_TYPE_STRING; + Value->Value.string =3D 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 =3D &OpCode->Value; + break; + + // + // unary-op + // + case EFI_IFR_LENGTH_OP: + Status =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Value->Type !=3D EFI_IFR_TYPE_STRING) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + StrPtr =3D GetToken (Value->Value.string, FormSet->UnicodeBinary); + if (StrPtr =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + Value->Type =3D EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 =3D FceStrLen (StrPtr); + FreePool (StrPtr); + break; + + case EFI_IFR_NOT_OP: + Status =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Value->Type !=3D EFI_IFR_TYPE_BOOLEAN) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + Value->Value.b =3D (BOOLEAN) (!Value->Value.b); + break; + + case EFI_IFR_QUESTION_REF2_OP: + // + // Pop an expression from the expression stack + // + Status =3D 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 =3D EFI_NOT_FOUND; + goto Done; + } + + Question =3D IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Done; + } + + Value =3D &Question->HiiValue; + break; + + case EFI_IFR_STRING_REF2_OP: + // + // Pop an expression from the expression stack + // + Status =3D 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 =3D EFI_NOT_FOUND; + goto Done; + } + + Value->Type =3D EFI_IFR_TYPE_STRING; + StrPtr =3D GetToken (Value->Value.u16, FormSet->UnicodeBinary); + if (StrPtr =3D=3D NULL) { + // + // If String not exit, push an empty string + // + //Value->Value.string =3D NewString (gEmptyString, FormSet->HiiHan= dle); + } else { + Index =3D (UINT16) Value->Value.u64; + Value->Value.string =3D Index; + FreePool (StrPtr); + } + break; + + case EFI_IFR_TO_BOOLEAN_OP: + // + // Pop an expression from the expression stack + // + Status =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Convert an expression to a Boolean + // + if (Value->Type <=3D EFI_IFR_TYPE_DATE) { + // + // When converting from an unsigned integer, zero will be conver= ted to + // FALSE and any other value will be converted to TRUE. + // + Value->Value.b =3D (BOOLEAN) (Value->Value.u64 !=3D 0); + + Value->Type =3D EFI_IFR_TYPE_BOOLEAN; + } else if (Value->Type =3D=3D EFI_IFR_TYPE_STRING) { + // + // When converting from a string, if case-insensitive compare + // with "true" is True, then push True. If a case-insensitive co= mpare + // with "false" is True, then push False. Otherwise, push Undefi= ned. + // + StrPtr =3D GetToken (Value->Value.string, FormSet->UnicodeBinary= ); + if (StrPtr =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + IfrStrToUpper (StrPtr); + if (FceStrCmp (StrPtr, L"TRUE") =3D=3D 0){ + Value->Value.b =3D TRUE; + } else if (FceStrCmp (StrPtr, L"FALSE") =3D=3D 0) { + Value->Value.b =3D FALSE; + } else { + Status =3D EFI_INVALID_PARAMETER; + FreePool (StrPtr); + goto Done; + } + FreePool (StrPtr); + Value->Type =3D EFI_IFR_TYPE_BOOLEAN; + } + break; + + case EFI_IFR_TO_STRING_OP: + //Status =3D IfrToString (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_TO_UINT_OP: + Status =3D IfrToUint (FormSet, Value); + break; + + case EFI_IFR_TO_LOWER_OP: + case EFI_IFR_TO_UPPER_OP: + + Status =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value->Type !=3D EFI_IFR_TYPE_STRING) { + Status =3D EFI_UNSUPPORTED; + goto Done; + } + + StrPtr =3D GetToken (Value->Value.string, FormSet->UnicodeBinary); + if (StrPtr =3D=3D NULL) { + Status =3D 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 =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Value->Type > EFI_IFR_TYPE_DATE) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + Value->Type =3D EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 =3D ~Value->Value.u64; + break; + + case EFI_IFR_SET_OP: + // + // Pop an expression from the expression stack + // + Status =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + Data1.Type =3D EFI_IFR_TYPE_BOOLEAN; + Data1.Value.b =3D FALSE; + // + // Not support SetOpcode for static scaning + // + if (OpCode->VarStorage !=3D NULL) { + switch (OpCode->VarStorage->Type) { + + case EFI_IFR_VARSTORE_OP: + CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOff= set, &Value->Value, OpCode->ValueWidth); + Data1.Value.b =3D TRUE; + break; + case EFI_IFR_VARSTORE_EFI_OP: + if (OpCode->VarStorage->NewEfiVarstore) { + CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.V= arOffset, &Value->Value, OpCode->ValueWidth); + Data1.Value.b =3D TRUE; + } else { + CopyMem (OpCode->VarStorage->Buffer, &Value->Value, OpCode->Valu= eWidth); + Data1.Value.b =3D TRUE; + } + break; + case EFI_HII_VARSTORE_NAME_VALUE: + + break; + break; + default: + // + // Not recognize storage. + // + Status =3D EFI_UNSUPPORTED; + goto Done; + break; + } + Value =3D &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 =3D PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Data2.Type > EFI_IFR_TYPE_DATE) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Pop another expression from the expression stack + // + Status =3D PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Data1.Type > EFI_IFR_TYPE_DATE) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + Value->Type =3D EFI_IFR_TYPE_NUM_SIZE_64; + + switch (OpCode->Operand) { + case EFI_IFR_ADD_OP: + Value->Value.u64 =3D Data1.Value.u64 + Data2.Value.u64; + break; + + case EFI_IFR_SUBTRACT_OP: + Value->Value.u64 =3D Data1.Value.u64 - Data2.Value.u64; + break; + + case EFI_IFR_MULTIPLY_OP: + Value->Value.u64 =3D MultU64x32 (Data1.Value.u64, (UINT32) Data2= .Value.u64); + break; + + case EFI_IFR_DIVIDE_OP: + Value->Value.u64 =3D 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 =3D TempValue; + break; + + case EFI_IFR_BITWISE_AND_OP: + Value->Value.u64 =3D Data1.Value.u64 & Data2.Value.u64; + break; + + case EFI_IFR_BITWISE_OR_OP: + Value->Value.u64 =3D Data1.Value.u64 | Data2.Value.u64; + break; + + case EFI_IFR_SHIFT_LEFT_OP: + Value->Value.u64 =3D LShiftU64 (Data1.Value.u64, (UINTN) Data2.V= alue.u64); + break; + + case EFI_IFR_SHIFT_RIGHT_OP: + Value->Value.u64 =3D RShiftU64 (Data1.Value.u64, (UINTN) Data2.V= alue.u64); + break; + + default: + break; + } + break; + + case EFI_IFR_AND_OP: + case EFI_IFR_OR_OP: + // + // Two Boolean operator + // + Status =3D PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Data2.Type !=3D EFI_IFR_TYPE_BOOLEAN) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Pop another expression from the expression stack + // + Status =3D PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Data1.Type !=3D EFI_IFR_TYPE_BOOLEAN) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + if (OpCode->Operand =3D=3D EFI_IFR_AND_OP) { + Value->Value.b =3D (BOOLEAN) (Data1.Value.b && Data2.Value.b); + } else { + Value->Value.b =3D (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 =3D PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + if ((Data2.Type > EFI_IFR_TYPE_BOOLEAN) && (Data2.Type !=3D EFI_IFR_= TYPE_STRING)) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Pop another expression from the expression stack + // + Status =3D PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + + Result =3D CompareHiiValue (&Data1, &Data2, FormSet); + if ((EFI_STATUS)Result =3D=3D EFI_INVALID_PARAMETER) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + switch (OpCode->Operand) { + case EFI_IFR_EQUAL_OP: + Value->Value.b =3D (BOOLEAN) ((Result =3D=3D 0) ? TRUE : FALSE); + break; + + case EFI_IFR_NOT_EQUAL_OP: + Value->Value.b =3D (BOOLEAN) ((Result !=3D 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_EQUAL_OP: + Value->Value.b =3D (BOOLEAN) ((Result >=3D 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_THAN_OP: + Value->Value.b =3D (BOOLEAN) ((Result > 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_EQUAL_OP: + Value->Value.b =3D (BOOLEAN) ((Result <=3D 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_THAN_OP: + Value->Value.b =3D (BOOLEAN) ((Result < 0) ? TRUE : FALSE); + break; + + default: + break; + } + break; + + case EFI_IFR_MATCH_OP: + Status =3D IfrMatch (FormSet, Value); + break; + + case EFI_IFR_CATENATE_OP: + Status =3D IfrCatenate (FormSet, Value); + break; + + // + // ternary-op + // + case EFI_IFR_CONDITIONAL_OP: + // + // Pop third expression from the expression stack + // + Status =3D PopExpression (&Data3); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Pop second expression from the expression stack + // + Status =3D PopExpression (&Data2); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Pop first expression from the expression stack + // + Status =3D PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + if (Data1.Type !=3D EFI_IFR_TYPE_BOOLEAN) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + + if (Data1.Value.b) { + Value =3D &Data3; + } else { + Value =3D &Data2; + } + break; + + case EFI_IFR_FIND_OP: + Status =3D IfrFind (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_MID_OP: + Status =3D IfrMid (FormSet, Value); + break; + + case EFI_IFR_TOKEN_OP: + Status =3D IfrToken (FormSet, Value); + break; + + case EFI_IFR_SPAN_OP: + Status =3D IfrSpan (FormSet, OpCode->Flags, Value); + break; + + case EFI_IFR_MAP_OP: + // + // Pop the check value + // + Status =3D PopExpression (&Data1); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Check MapExpression list is valid. + // + if (OpCode->MapExpressionList.ForwardLink =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + // + // Go through map expression list. + // + SubExpressionLink =3D GetFirstNode(&OpCode->MapExpressionList); + while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + SubExpression =3D FORM_EXPRESSION_FROM_LINK (SubExpressionLink); + // + // Evaluate the first expression in this pair. + // + Status =3D EvaluateExpression (FormSet, Form, SubExpression, Const= antExpression); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Compare the expression value with current value + // + if (CompareHiiValue (&Data1, &SubExpression->Result, FormSet) =3D= =3D 0) { + // + // Try get the map value. + // + SubExpressionLink =3D GetNextNode (&OpCode->MapExpressionList, S= ubExpressionLink); + if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + SubExpression =3D FORM_EXPRESSION_FROM_LINK (SubExpressionLink); + Status =3D EvaluateExpression (FormSet, Form, SubExpression, Con= stantExpression); + if (EFI_ERROR (Status)) { + goto Done; + } + Value =3D &SubExpression->Result; + break; + } + // + // Skip the second expression on this pair. + // + SubExpressionLink =3D GetNextNode (&OpCode->MapExpressionList, Sub= ExpressionLink); + if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + Status =3D EFI_INVALID_PARAMETER; + goto Done; + } + // + // Goto the first expression on next pair. + // + SubExpressionLink =3D GetNextNode (&OpCode->MapExpressionList, Sub= ExpressionLink); + } + + // + // No map value is found. + // + if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) { + Value->Type =3D EFI_IFR_TYPE_UNDEFINED; + Value->Value.u8 =3D 0; + } + break; + + default: + break; + } + if (EFI_ERROR (Status)) { + goto Done; + } + + Status =3D PushExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Pop the final result from expression stack + // + Value =3D &Data1; + Status =3D PopExpression (Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // After evaluating an expression, there should be only one value left o= n the expression stack + // + if (PopExpression (Value) !=3D EFI_ACCESS_DENIED) { + Status =3D 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 configu= ration ("Setup") + data in Firmware Device files (".fd" files). + + Copyright (c) 2011-2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Fce.h" + +#ifndef __GNUC__ +#define COPY_STR "copy \"%s\" \"%s\" > NUL" +#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL" +#define DEL_STR "del \"%s\" > NUL" +#else +#define COPY_STR "cp \"%s\" \"%s\" > /dev/null" +#define RMDIR_STR "rm -r \"%s\" > /dev/null" +#define DEL_STR "rm \"%s\" > /dev/null" +#endif + +// +// Utility global variables +// +OPERATION_TYPE Operations; + +CHAR8 mInputFdName[MAX_FILENAME_LEN]; +CHAR8 mOutputFdName[MAX_FILENAME_LEN]; +CHAR8 mOutTxtName[MAX_FILENAME_LEN]; +CHAR8 mSetupTxtName[MAX_FILENAME_LEN]; + +CHAR8* mUtilityFilename =3D NULL; +UINT32 mEfiVariableAddr =3D 0; + +UQI_PARAM_LIST *mUqiList =3D NULL; +UQI_PARAM_LIST *mLastUqiList =3D NULL; +LIST_ENTRY mVarListEntry; +LIST_ENTRY mBfvVarListEntry; +LIST_ENTRY mAllVarListEntry; +LIST_ENTRY mFormSetListEntry; + +// +// Store GUIDed Section guid->tool mapping +// +EFI_HANDLE mParsedGuidedSectionTools =3D NULL; + +CHAR8* mGuidToolDefinition =3D "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 =3D 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 =3D NULL; + SystemCommand =3D NULL; + TempSystemCommand =3D NULL; + Revision =3D "Revision.txt"; + + memset (RevisionStr, 0, _MAX_BUILD_VERSION); + + // + // Construction 'system' command string + // + SystemCommandFormatString =3D "BfmLib -v > %s"; + SystemCommand =3D malloc ( + strlen (SystemCommandFormatString) + strlen (Revision)= + 1 + ); + if (SystemCommand =3D=3D NULL) { + return EFI_UNSUPPORTED; + } + sprintf ( + SystemCommand, + "BfmLib -v > %s", + Revision + ); + + if (mFullGuidToolDefinitionDir[0] !=3D 0) { + TempSystemCommand =3D SystemCommand; + SystemCommand =3D malloc ( + strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_S= TR) + strlen (SystemCommandFormatString) + strlen (Revision) + 1 + ); + + if (SystemCommand =3D=3D NULL) { + free (TempSystemCommand); + return EFI_UNSUPPORTED; + } + strcpy (SystemCommand, mFullGuidToolDefinitionDir); + strcat (SystemCommand, OS_SEP_STR); + strcat (SystemCommand, TempSystemCommand); + free (TempSystemCommand); + } + + system (SystemCommand); + free (SystemCommand); + FileHandle =3D fopen (Revision, "r"); + if (FileHandle =3D=3D NULL) { + printf ("Error. Read the revision file of BfmLib failed.\n"); + return EFI_ABORTED; + } + fgets(RevisionStr, _MAX_BUILD_VERSION, FileHandle); + Len =3D strlen(RevisionStr); + if (RevisionStr[Len - 1] =3D=3D '\n') { + RevisionStr[Len - 1] =3D 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) =3D=3D 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 =3D 0; + DecNum =3D 0; + Temp =3D 0; + + if (InStr =3D=3D NULL) { + return (UINT64)-1; + } + while (Index < strlen (InStr)) { + + if ((*(InStr + Index) >=3D '0') && (*(InStr + Index) <=3D '9')) { + Temp =3D *(InStr + Index) - '0'; + } else if ((*(InStr + Index) >=3D 'a') && (*(InStr + Index) <=3D 'f'))= { + Temp =3D *(InStr + Index) - 'a' + 10; + } else if ((*(InStr + Index) >=3D 'A') && (*(InStr + Index) <=3D 'F'))= { + Temp =3D *(InStr + Index) - 'A' + 10; + } + DecNum =3D 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 =3D NULL; + Option =3D NULL; + Value =3D 0; + + Link =3D GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option =3D QUESTION_OPTION_FROM_LINK (Link); + Value =3D 0; + CopyMem (&Value, &Option->Value.Value.u64, Question->StorageWidth); + if (Value =3D=3D UqiValue) { + return FALSE; + } + Link =3D 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 =3D UqiValue[0]; + + if (MaxNum !=3D (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 =3D=3D NULL) { + return; + } + + for (Index =3D 0; pcString[Index] !=3D 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 com= pare 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 =3D NULL; + Index =3D 0; + ValueAddrOfVar =3D NULL; + QuestionValue =3D 0; + UqiValue =3D 0; + ErrorStr =3D NULL; + Status =3D EFI_SUCCESS; + FormSet =3D NULL; + FormSetLink =3D NULL; + CurValue =3D 0; + + // + // Search the Variable List by VarStoreId and Offset + // + IsFound =3D FALSE; + FormSetLink =3D GetFirstNode (&mFormSetListEntry); + while (!IsNull (&mFormSetListEntry, FormSetLink)) { + FormSet =3D FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink); + Status =3D SearchVarStorage ( + CurQuestion, + NULL, + CurQuestion->VarStoreInfo.VarOffset, + FormSet->StorageListHead, + (CHAR8 **) &ValueAddrOfVar, + &VarList + ); + + if (!EFI_ERROR (Status)) { + IsFound =3D TRUE; + break; + } + FormSetLink =3D GetNextNode (&mFormSetListEntry, FormSetLink); + } + + if (!IsFound) { + if (CurUqiList->Header.ScriptsLine =3D=3D 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.S= criptsLine); + } + return EFI_ABORTED; + } + + // + // Check the length of variable value + // + if (CurQuestion->QuestionReferToBitField) { + GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)&QuestionV= alue); + } else { + switch (CurQuestion->StorageWidth) { + + case sizeof (UINT8): + QuestionValue =3D *(UINT8 *)ValueAddrOfVar; + break; + + case sizeof (UINT16): + QuestionValue =3D *(UINT16 *)ValueAddrOfVar; + break; + + case sizeof (UINT32): + QuestionValue =3D *(UINT32 *)ValueAddrOfVar; + break; + + case sizeof (UINT64): + QuestionValue =3D *(UINT64 *)ValueAddrOfVar; + break; + + default: + // + // The storage width of ORDERED_LIST may not be any type above. + // + ; + break; + } + } + UqiValue =3D *(UINT64 *)CurUqiList->Header.Value; + CurUqiList->SameOrNot =3D TRUE; + + // + // Check and set the checkbox value + // + if (CurQuestion->Operand =3D=3D EFI_IFR_CHECKBOX_OP) { + if ((UqiValue !=3D 0) && (UqiValue !=3D 1)) { + CurUqiList->ErrorOrNot =3D TRUE; + CurUqiList->SameOrNot =3D FALSE; + CurUqiList->Error =3D malloc (ERROR_INFO_LENGTH * sizeof (CHAR8= )); + if (CurUqiList->Error =3D=3D 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*)CurUqi= List->Header.DiffValue); + } else { + memcpy ( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + } + } else { + if (QuestionValue !=3D UqiValue) { + if (CurQuestion->QuestionReferToBitField) { + GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurU= qiList->Header.DiffValue); + SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)Cur= UqiList->Header.Value); + } else { + memcpy ( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + memcpy ( + ValueAddrOfVar, + CurUqiList->Header.Value, + CurQuestion->StorageWidth + ); + } + CurUqiList->SameOrNot =3D FALSE; + } + } + } + if (CurQuestion->Operand =3D=3D EFI_IFR_STRING_OP) { + if ((FceStrLen((wchar_t *)CurUqiList->Header.Value) + 1) * 2 > CurQuest= ion->StorageWidth) { + CurUqiList->ErrorOrNot =3D TRUE; + CurUqiList->Error =3D malloc (ERROR_INFO_LENGTH * sizeof (CHAR8)); + if (CurUqiList->Error =3D=3D 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 excee= d its Size.\n"); + memcpy ( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + } else { + if (memcmp((CHAR8 *)CurUqiList->Header.Value, ValueAddrOfVar, CurQues= tion->StorageWidth) !=3D 0) { + memcpy( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + memcpy( + ValueAddrOfVar, + CurUqiList->Header.Value, + CurQuestion->StorageWidth + ); + CurUqiList->SameOrNot =3D FALSE; + } + } + } + // + // Check and set the NUMERIC value + // + if (CurQuestion->Operand =3D=3D EFI_IFR_NUMERIC_OP) { + if ((UqiValue < CurQuestion->Minimum) || (UqiValue > CurQuestion->Maxi= mum)) { + CurUqiList->ErrorOrNot =3D TRUE; + CurUqiList->SameOrNot =3D FALSE; + CurUqiList->Error =3D malloc (ERROR_INFO_LENGTH * sizeof (CHAR8)); + if (CurUqiList->Error =3D=3D 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*)CurUqi= List->Header.DiffValue); + } else { + memcpy ( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + } + } else { + if (QuestionValue !=3D UqiValue) { + if (CurQuestion->QuestionReferToBitField) { + GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurU= qiList->Header.DiffValue); + SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)Cur= UqiList->Header.Value); + } else { + memcpy ( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + memcpy ( + ValueAddrOfVar, + CurUqiList->Header.Value, + CurQuestion->StorageWidth + ); + } + CurUqiList->SameOrNot =3D FALSE; + } + } + } + // + // Check and set the ONE_OF value + // + if (CurQuestion->Operand =3D=3D EFI_IFR_ONE_OF_OP) { + if (CheckOneOfParamError (CurQuestion, UqiValue)) { + CurUqiList->ErrorOrNot =3D TRUE; + CurUqiList->SameOrNot =3D FALSE; + CurUqiList->Error =3D malloc (ERROR_INFO_LENGTH * sizeof (CHAR8)); + if (CurUqiList->Error =3D=3D 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*)CurUqi= List->Header.DiffValue); + } else { + memcpy ( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + } + } else { + if (QuestionValue !=3D UqiValue) { + if (CurQuestion->QuestionReferToBitField) { + GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurU= qiList->Header.DiffValue); + SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)Cur= UqiList->Header.Value); + } else { + memcpy ( + CurUqiList->Header.DiffValue, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + memcpy ( + ValueAddrOfVar, + CurUqiList->Header.Value, + CurQuestion->StorageWidth + ); + } + CurUqiList->SameOrNot =3D FALSE; + } + } + } + // + // Check and set the ORDER_LIST value + // + if (CurQuestion->Operand =3D=3D EFI_IFR_ORDERED_LIST_OP) { + // + // Synchronize the MaxContainers value + // + *CurUqiList->Header.DiffValue =3D (UINT8)CurQuestion->MaxContainers; + + if (CheckOrderParamError (CurQuestion, (CHAR8 *)CurUqiList->Header.Val= ue)) { + + CurUqiList->ErrorOrNot =3D TRUE; + CurUqiList->SameOrNot =3D FALSE; + CurUqiList->Error =3D malloc (ERROR_INFO_LENGTH * sizeof (CHAR8)); + if (CurUqiList->Error =3D=3D NULL) { + printf ("Fail to allocate memory!\n"); + return EFI_ABORTED; + } + memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH); + + ErrorStr =3D CurUqiList->Error; + sprintf (ErrorStr, "Error. The updated NORDERED_LIST value "); + ErrorStr =3D ErrorStr + strlen ("Error. The updated NORDERED_LIST va= lue "); + + for (Index =3D 0; Index < CurQuestion->StorageWidth; Index++) { + sprintf (ErrorStr, "%02x ", *(CurUqiList->Header.Value + Index + 1= )); + ErrorStr +=3D3; + } + sprintf (ErrorStr, "is invalid.\n"); + memcpy ( + CurUqiList->Header.DiffValue + 1, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + } else { + for (Index =3D 0; Index < CurQuestion->StorageWidth/CurQuestion->Max= Containers; Index++) { + CurValue =3D 0; + memcpy ( + &CurValue, + (ValueAddrOfVar + Index * CurQuestion->StorageWidth/CurQuestion-= >MaxContainers), + CurQuestion->StorageWidth/CurQuestion->MaxContainers + ); + if (CurValue !=3D *((UINT64 *)CurUqiList->Header.Value + Index + 1= )) { + CurUqiList->SameOrNot =3D FALSE; + break; + } + } + if (!CurUqiList->SameOrNot) { + memcpy ( + CurUqiList->Header.DiffValue + 1, + ValueAddrOfVar, + CurQuestion->StorageWidth + ); + for (Index =3D 0; Index < CurQuestion->MaxContainers; Index++) { + switch (CurQuestion->StorageWidth/CurQuestion->MaxContainers) { + + case sizeof (UINT8): + *((UINT8 *)ValueAddrOfVar + Index) =3D *(UINT8 *)((UINT64 *)Cu= rUqiList->Header.Value + 1 + Index); + break; + + case sizeof (UINT16): + *((UINT16 *)ValueAddrOfVar + Index) =3D *(UINT16 *)((UINT64 *)= CurUqiList->Header.Value + 1 + Index); + break; + + case sizeof (UINT32): + *((UINT32 *)ValueAddrOfVar + Index) =3D *(UINT32 *)((UINT64 *)= CurUqiList->Header.Value + 1 + Index); + break; + + case sizeof (UINT64): + *((UINT64 *)ValueAddrOfVar + Index) =3D *((UINT64 *)CurUqiList= ->Header.Value + 1 + Index); + break; + + default: + *((UINT8 *)ValueAddrOfVar + Index) =3D *(UINT8 *)((UINT64 *)Cu= rUqiList->Header.Value + 1 + Index); + break; + } + } + // + // Update the vaule of ORDERED_LIST according to its size + // + CurUqiList->Header.Value =3D (UINT8 *)((UINT64 *)CurUqiList->Heade= r.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 com= pare 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 =3D NULL; + FormSetLink =3D NULL; + Form =3D NULL; + FormLink =3D NULL; + Question =3D NULL; + QuestionLink =3D NULL; + FormSetEntryListHead =3D &mFormSetListEntry; + + FormSetLink =3D GetFirstNode (FormSetEntryListHead); + while (!IsNull (FormSetEntryListHead, FormSetLink)) { + FormSet =3D FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink); + // + // Parse all forms in formset + // + FormLink =3D GetFirstNode (&FormSet->FormListHead); + + while (!IsNull (&FormSet->FormListHead, FormLink)) { + Form =3D FORM_BROWSER_FORM_FROM_LINK (FormLink); + // + // Parse five kinds of Questions in Form + // + QuestionLink =3D GetFirstNode (&Form->StatementListHead); + + while (!IsNull (&Form->StatementListHead, QuestionLink)) { + Question =3D FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); + QuestionLink =3D GetNextNode (&Form->StatementListHead, QuestionLi= nk); + // + // Parse five kinds of Questions in Form + // + if ((Question->Operand =3D=3D EFI_IFR_ONE_OF_OP) + || (Question->Operand =3D=3D EFI_IFR_NUMERIC_OP) + || (Question->Operand =3D=3D EFI_IFR_CHECKBOX_OP) + || (Question->Operand =3D=3D EFI_IFR_ORDERED_LIST_OP) + || (Question->Operand =3D=3D EFI_IFR_STRING_OP) + ) { + if (mMultiPlatformParam.MultiPlatformOrNot) { + // + // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-pla= tform mode + // + if (Question->Type !=3D EFI_IFR_VARSTORE_EFI_OP) { + continue; + } + if ((Question->Type =3D=3D EFI_IFR_VARSTORE_EFI_OP) + && Question->NewEfiVarstore + && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) =3D= =3D 0)) { + continue; + } + } + + CurUqiList =3D UqiList; + while (CurUqiList !=3D NULL) { + if ((PlatformId =3D=3D CurUqiList->Header.PlatformId[0]) + && (DefaultId =3D=3D CurUqiList->Header.DefaultId[0]) + && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header)) + ) { + // + // Add further check to avoid a case that there are many opt= ions with a + // same UQI (en-Us), but always returns the first one. + // + if (!CurUqiList->ParseOrNot) { + CurUqiList->ParseOrNot =3D TRUE; + break; + } + } + CurUqiList =3D CurUqiList->Next; + } + if (CurUqiList !=3D NULL) { + SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformI= d, Question); + } + } + } + FormLink =3D GetNextNode (&FormSet->FormListHead, FormLink); + } + FormSetLink =3D 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 =3D UqiList; + while (CurUqiList !=3D NULL) { + if ((CurUqiList->ParseOrNot =3D=3D FALSE) + && (PlatformId =3D=3D CurUqiList->Header.PlatformId[0]) + && (DefaultId =3D=3D CurUqiList->Header.DefaultId[0]) + ) { + CurUqiList->ParseOrNot =3D TRUE; + if (CurUqiList->Header.Question !=3D NULL) { + SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, C= urUqiList->Header.Question); + } + } + CurUqiList =3D 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 =3D=3D NULL) { + return EFI_SUCCESS; + } + FormSet =3D NULL; + FormSetLink =3D NULL; + Form =3D NULL; + FormLink =3D NULL; + Question =3D NULL; + QuestionLink =3D NULL; + FormSetEntryListHead =3D &mFormSetListEntry; + + FormSetLink =3D FormSetEntryListHead->ForwardLink; + while (FormSetEntryListHead !=3D FormSetLink) { + FormSet =3D FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink); + // + // Parse all forms in formset + // + FormLink =3D FormSet->FormListHead.ForwardLink; + + while (&FormSet->FormListHead !=3D FormLink) { + Form =3D FORM_BROWSER_FORM_FROM_LINK (FormLink); + // + // Parse five kinds of Questions in Form + // + QuestionLink =3D Form->StatementListHead.ForwardLink; + + while (&Form->StatementListHead !=3D QuestionLink) { + Question =3D FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink); + QuestionLink =3D QuestionLink->ForwardLink; + // + // Parse five kinds of Questions in Form + // + if ((Question->Operand =3D=3D EFI_IFR_ONE_OF_OP) + || (Question->Operand =3D=3D EFI_IFR_NUMERIC_OP) + || (Question->Operand =3D=3D EFI_IFR_CHECKBOX_OP) + || (Question->Operand =3D=3D EFI_IFR_ORDERED_LIST_OP) + || (Question->Operand =3D=3D EFI_IFR_STRING_OP) + ) { + // + // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platf= orm mode + // + if (Question->Type !=3D EFI_IFR_VARSTORE_EFI_OP) { + continue; + } else if (Question->NewEfiVarstore + && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) =3D=3D = 0)) { + continue; + } + + CurUqiList =3D UqiList; + PlatformId =3D 0xFFFFFFFF; + DefaultId =3D 0xFFFF; + while (CurUqiList !=3D NULL) { + if ((CurUqiList->Header.Question =3D=3D NULL) + && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header)) + && ((PlatformId !=3D CurUqiList->Header.PlatformId[0]) || (D= efaultId !=3D CurUqiList->Header.DefaultId[0])) + ) { + CurUqiList->Header.Question =3D Question; + PlatformId =3D CurUqiList->Header.PlatformId[0]; + DefaultId =3D CurUqiList->Header.DefaultId[0]; + } + CurUqiList =3D CurUqiList->Next; + } + } + } + FormLink =3D FormLink->ForwardLink; + } + FormSetLink =3D 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 =3D (UQI_PARAM_LIST *) malloc (sizeof (UQI_PARAM_LIST)); + if (Node =3D=3D NULL) { + return NULL; + } + memset (Node, 0, sizeof (UQI_PARAM_LIST)); + + if (mUqiList =3D=3D NULL) { + mUqiList =3D Node; + } else { + mLastUqiList->Next =3D Node; + } + + mLastUqiList =3D Node; + return Node; +} +/** + Parse the first part of QUI string + + @param **argv[] The dual array pointer to the paramet= ers. + @param Number The pointer to the number of the firs= t 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 =3D 0; + + *Number =3D (UINT32)StrToDec ((*argv)[0]); + + if ((*Number <=3D 0) || (*Number > MAX_QUI_PARAM_LEN)) { + printf ("Error. Invalid UQI.\n"); + return EFI_INVALID_PARAMETER; + } + + *Buffer =3D malloc ((*Number + 1) * sizeof (CHAR16)); + assert (*Buffer !=3D NULL); + memset (*Buffer, 0, (*Number + 1) * sizeof (CHAR16)); + + for (Index =3D 0; Index < *Number; Index++) { + if (StrToDec ((*argv)[Index]) > 0xff) { + printf ("Error. Invalid UQI.\n"); + return EFI_INVALID_PARAMETER; + } + *(*Buffer + Index) =3D (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 pa= rameters. + @param **argv[] The dual array pointer to the paramet= ers. + + @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 =3D 0; + UqiNode =3D NULL; + + if (*argc < 4) { + printf ("Error. The correct command is 'FCE updateq -i -o '.\n"); + return EFI_INVALID_PARAMETER; + } + + UqiNode =3D CreateInsertUqiNode (); + assert (UqiNode !=3D NULL); + + UqiNode->Header.DefaultId =3D (UINT16 *) calloc (1, sizeof (UINT16)); + UqiNode->Header.PlatformId =3D (UINT64 *) calloc (1, sizeof (UINT64)); + + Status =3D ParseFirstpartOfUqi (argv, &(UqiNode->Header.HexNum), &(UqiNo= de->Header.Data)); + if (EFI_ERROR (Status)) { + return Status; + } + *argc -=3D (UqiNode->Header.HexNum + 1); + *argv +=3D UqiNode->Header.HexNum + 1; + // + // Parse the TYPE and value + // + if (strcmp ("ONE_OF", (*argv)[0]) =3D=3D 0) { + UqiNode->Header.Type =3D ONE_OF; + } else if (strcmp ("NUMERIC", (*argv)[0]) =3D=3D 0) { + UqiNode->Header.Type =3D NUMERIC; + } else if (strcmp ("CHECKBOX", (*argv)[0]) =3D=3D 0) { + UqiNode->Header.Type =3D CHECKBOX; + } else if (strcmp ("STRING", (*argv)[0]) =3D=3D 0) { + UqiNode->Header.Type =3D STRING; + } else if (strcmp ("ORDERED_LIST", (*argv)[0]) =3D=3D 0) { + UqiNode->Header.Type =3D ORDERED_LIST; + } else { + printf ("Error. The correct command is 'FCE updateq -i -o '.\n"); + return EFI_INVALID_PARAMETER; + } + *argc -=3D 1; + *argv +=3D 1; + // + // Get the value according to the type of questions. + // + switch (UqiNode->Header.Type) { + + case ONE_OF: + case NUMERIC: + case CHECKBOX: + UqiNode->Header.Value =3D malloc (sizeof (UINT64)); + if (UqiNode->Header.Value =3D=3D NULL) { + printf ("Fali to allocate memory!\n"); + return EFI_OUT_OF_RESOURCES; + } + memset (UqiNode->Header.Value, 0, sizeof (UINT64)); + + UqiNode->Header.DiffValue =3D malloc (sizeof (UINT64)); + if (UqiNode->Header.DiffValue =3D=3D NULL) { + printf ("Fali to allocate memory!\n"); + return EFI_OUT_OF_RESOURCES; + } + memset ( + UqiNode->Header.DiffValue, + 0, + sizeof (UINT64) + ); + *(UINT64 *)(UqiNode->Header.Value) =3D (UINT64)StrToDec ((*argv)[0]); + break; + + case ORDERED_LIST: + UqiNode->Header.Value =3D malloc (((UINTN)StrToDec ((*argv)[0]) + 1= ) * sizeof (UINT64)); + if (UqiNode->Header.Value =3D=3D 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 =3D malloc (((UINTN)StrToDec ((*argv)[0])= + 1) * sizeof (UINT64)); + if (UqiNode->Header.DiffValue =3D=3D 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 =3D (UINT8)StrToDec ((*argv)[0]); + for (Index =3D 1; Index <=3D StrToDec ((*argv)[0]); Index++) { + *((UINT64 *)UqiNode->Header.Value + Index) =3D StrToDec ((*argv)[Ind= ex]); + } + *argc -=3D (UINTN)StrToDec ((*argv)[0]); + *argv +=3D (UINTN)StrToDec ((*argv)[0]); + break; + + default: + break; + } + + *argc -=3D 1; + *argv +=3D 1; + + if (*argc > 0) { + printf ("Error. The correct command is 'FCE updateq -i -o '.\n"); + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} +/** + Parse the input Fd file, and get the file name according to the FILETYPE. + + @param FdName The Name of Fd file + @param FILETYPE The type of Fd file + + @return EFI_SUCCESS Get the file name successfully + @return EFI_ABORTED An error occurred. +**/ +static +EFI_STATUS +ParseInFile ( + IN CHAR8 *FdName, + IN FILETYPE Type +) +{ + FILE *Fptr; + + Fptr =3D NULL; + + if ((Type =3D=3D INFD) && ((FdName =3D=3D NULL) || (Fptr =3D fopen (FdNa= me, "r")) =3D=3D NULL)) { + if (FdName !=3D NULL) { + printf ("Error: The file doesn't exist '%s'\n", FdName); + } + return EFI_ABORTED; + } + if ((Type =3D=3D OUTFD) && (FdName =3D=3D NULL) ) { + printf ("Error: The name is NULL.\n"); + return EFI_ABORTED; + } + if ((Type =3D=3D SETUPTXT) && (FdName =3D=3D NULL) ) { + printf ("Error: The