mirror of
https://github.com/acidanthera/audk.git
synced 2025-05-20 14:30:11 +02:00
FMMT is a tool to enable removal, addition and replacement of FFS files in FD image binaries. https://bugzilla.tianocore.org/show_bug.cgi?id=1847 Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <liming.gao@intel.com> Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
2560 lines
83 KiB
C
2560 lines
83 KiB
C
/** @file
|
|
|
|
FMMT main routine.
|
|
|
|
Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "FirmwareModuleManagement.h"
|
|
#include "Rebase.h"
|
|
#include <stdlib.h>
|
|
#include <wchar.h>
|
|
|
|
CHAR8* mGuidToolDefinition = "FmmtConf.ini";
|
|
extern EFI_FIRMWARE_VOLUME_HEADER *mFvHeader;
|
|
extern UINT32 mFvLength;
|
|
|
|
//
|
|
// Store GUIDed Section guid->tool mapping
|
|
//
|
|
EFI_HANDLE mParsedGuidedSectionTools = NULL;
|
|
#define EFI_FFS_VOLUME_TOP_FILE_GUID \
|
|
{ \
|
|
0x1BA0062E, 0xC779, 0x4582, { 0x85, 0x66, 0x33, 0x6A, 0xE8, 0xF7, 0x8F, 0x09 } \
|
|
}
|
|
#define FSP_FFS_INFORMATION_FILE_GUID \
|
|
{ 0x912740be, 0x2284, 0x4734, { 0xb9, 0x71, 0x84, 0xb0, 0x27, 0x35, 0x3f, 0x0c }};
|
|
|
|
static EFI_GUID mVTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
|
|
static EFI_GUID mFSPGuid = FSP_FFS_INFORMATION_FILE_GUID;
|
|
|
|
|
|
/**
|
|
|
|
Routine Description:
|
|
|
|
The Usage of FMMT tool.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
**/
|
|
VOID
|
|
Usage (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Summary usage
|
|
//
|
|
fprintf (stdout, "Usage: %s [options] \n\n", UTILITY_SHORT_NAME);
|
|
|
|
//
|
|
// Copyright declaration
|
|
//
|
|
fprintf (stdout, "Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.\n\n");
|
|
|
|
//
|
|
// Details Option
|
|
//
|
|
fprintf (stdout, "Options:\n");
|
|
|
|
//
|
|
// Command Line for View
|
|
//
|
|
fprintf (stdout, " -v <input-binary-file>\n\
|
|
View each FV and the named files within each FV.\n");
|
|
|
|
//
|
|
// Command Line for Delete entire FV
|
|
//
|
|
fprintf (stdout, " -d <input-binary-file> <FV-id> <output-binary-file>\n\
|
|
Delete the entire FV in an FD binary\n");
|
|
|
|
//
|
|
// Command Line for Delete file from FV
|
|
//
|
|
fprintf (stdout, " -d <input-binary-file> <FV-id> <File-Name> [<FV-id> <File-Name> ...] <output-binary-file>\n\
|
|
Delete a file (or files) from the firmware volume in an FD binary\n");
|
|
|
|
//
|
|
// Command Line for Add
|
|
//
|
|
fprintf (stdout, " -a <input-binary-file> <FV-id> <NewFilePath> [<FV-id> <NewFilePath> ...] <output-binary-file>\n\
|
|
Add a file (or files) to the firmware volume in an FD binary\n");
|
|
|
|
//
|
|
// Command Line for Replace
|
|
//
|
|
fprintf (stdout, " -r <input-binary-file> <FV-id> <File-Name> <NewFilePath> [<FV-id> <File-Name> <NewFilePath> ...] <output-binary-file>\n\
|
|
The replace command combines the functionality of remove and add into a single operation.\n");
|
|
|
|
fprintf (stdout, "\nNote:\n");
|
|
fprintf (stdout, " <FV-id> is the sequence of the firmware volume included in the FD image, it both support the sequentially format like FV0, FV1 and the FV's file guid value format.\n");
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IsVtf(EFI_FFS_FILE_HEADER2* ffs) {
|
|
if (!memcmp(&ffs->Name, &mVTFGuid, sizeof (EFI_GUID))) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IsFsp(EFI_FFS_FILE_HEADER2* ffs) {
|
|
if (!memcmp(&ffs->Name, &mFSPGuid, sizeof (EFI_GUID))) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static
|
|
EFI_STATUS
|
|
GetBaseAddrFromVtf(FIRMWARE_DEVICE *FdData, CHAR8 *FvId, UINT64 *BaseAddr) {
|
|
EFI_STATUS Status;
|
|
FV_INFORMATION *CurrentFv;
|
|
FV_INFORMATION *FvInFd;
|
|
|
|
Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get bottom FV
|
|
//
|
|
CurrentFv = FdData->Fv;
|
|
while (CurrentFv->FvNext) {
|
|
CurrentFv = CurrentFv->FvNext;
|
|
}
|
|
if (CurrentFv->FfsNumbers > 0 && IsVtf(&CurrentFv->FfsHeader[CurrentFv->FfsNumbers])) {
|
|
//
|
|
// Found VTF at the top of FV
|
|
// Assume 4G address
|
|
//
|
|
*BaseAddr = 0x100000000 - (FdData->Size - FvInFd->ImageAddress);
|
|
return EFI_SUCCESS;
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
static
|
|
EFI_STATUS
|
|
GetBaseAddrFromFsp(FIRMWARE_DEVICE *FdData, CONST UINT8* FdBuffer, CHAR8 *FvId, UINT64 *BaseAddr)
|
|
{
|
|
EFI_STATUS Status;
|
|
FV_INFORMATION *FvInFd;
|
|
FV_INFORMATION *CurrentFv;
|
|
FV_INFORMATION *FspFv;
|
|
UINT32 Offset;
|
|
UINT64 ImageSize;
|
|
UINT64 Size;
|
|
EFI_FFS_FILE_HEADER2 *CurrentFile;
|
|
BOOLEAN FspFound;
|
|
|
|
Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ImageSize = 0;
|
|
Size = 0;
|
|
FspFound = FALSE;
|
|
FspFv = NULL;
|
|
CurrentFv = FdData->Fv;
|
|
while (CurrentFv) {
|
|
if (CurrentFv->FfsNumbers > 0 && IsFsp(&CurrentFv->FfsHeader[0])) {
|
|
Offset = CurrentFv->ImageAddress + CurrentFv->FfsAttuibutes[0].Offset;
|
|
CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
|
|
//
|
|
// Skip FFS header
|
|
//
|
|
Offset += GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)CurrentFile);
|
|
//
|
|
// Stip section header
|
|
//
|
|
Offset += GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)(FdBuffer + Offset));
|
|
//
|
|
// We have raw FSP here, and 24 is the image size
|
|
//
|
|
ImageSize = *((UINT32 *)(FdBuffer + Offset + 24));
|
|
//
|
|
// 28 is the base address
|
|
//
|
|
*BaseAddr = *((UINT32 *)(FdBuffer + Offset + 28));
|
|
FspFound = TRUE;
|
|
FspFv = CurrentFv;
|
|
}
|
|
if (CurrentFv == FvInFd){
|
|
break;
|
|
}
|
|
CurrentFv = CurrentFv->FvNext;
|
|
}
|
|
if (!FspFound) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
//
|
|
// Check if FSP binary contains this FV
|
|
//
|
|
while (FspFv != NULL) {
|
|
Size += FspFv->FvHeader->FvLength;
|
|
if (FspFv == FvInFd) {
|
|
break;
|
|
}
|
|
FspFv = FspFv->FvNext;
|
|
}
|
|
if (Size <= ImageSize) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
AddPadFile(EFI_FIRMWARE_VOLUME_HEADER *Fv, EFI_FFS_FILE_HEADER2 *PadFile, UINT32 PadFileSize) {
|
|
UINT32 hdrSize;
|
|
|
|
if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
memset(PadFile, -1, PadFileSize);
|
|
}
|
|
else {
|
|
memset(PadFile, 0, PadFileSize);
|
|
}
|
|
PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
|
|
PadFile->Attributes = 0;
|
|
|
|
//
|
|
// Write pad file size (calculated size minus next file header size)
|
|
//
|
|
if (PadFileSize >= MAX_FFS_SIZE) {
|
|
memset(PadFile->Size, 0, sizeof(UINT8)* 3);
|
|
((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize;
|
|
PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
|
|
hdrSize = sizeof(EFI_FFS_FILE_HEADER2);
|
|
}
|
|
else {
|
|
PadFile->Size[0] = (UINT8)(PadFileSize & 0xFF);
|
|
PadFile->Size[1] = (UINT8)((PadFileSize >> 8) & 0xFF);
|
|
PadFile->Size[2] = (UINT8)((PadFileSize >> 16) & 0xFF);
|
|
hdrSize = sizeof(EFI_FFS_FILE_HEADER);
|
|
}
|
|
|
|
//
|
|
// Fill in checksums and state, they must be 0 for checksumming.
|
|
//
|
|
PadFile->IntegrityCheck.Checksum.Header = 0;
|
|
PadFile->IntegrityCheck.Checksum.File = 0;
|
|
PadFile->State = 0;
|
|
PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8((UINT8 *)PadFile, hdrSize);
|
|
PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
|
|
|
|
PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
|
|
if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
PadFile->State = (UINT8)~(PadFile->State);
|
|
}
|
|
}
|
|
|
|
static
|
|
UINT8* ReadFileToBuffer(CONST CHAR8 *FdName, UINT32 *FdSize) {
|
|
FILE* file;
|
|
|
|
UINT8 *FdBuffer = NULL;
|
|
|
|
file = fopen(FdName, "rb");
|
|
if (file == NULL)
|
|
return NULL;
|
|
|
|
fseek(file, 0, SEEK_SET);
|
|
fseek(file, 0, SEEK_END);
|
|
*FdSize = ftell(file);
|
|
fseek(file, 0, SEEK_SET);
|
|
|
|
FdBuffer = malloc(*FdSize);
|
|
if (FdBuffer == NULL) {
|
|
goto FAIL;
|
|
}
|
|
if (fread(FdBuffer, 1, *FdSize, file) != *FdSize) {
|
|
goto FAIL;
|
|
}
|
|
fclose(file);
|
|
return FdBuffer;
|
|
FAIL:
|
|
free(FdBuffer);
|
|
fclose(file);
|
|
return NULL;
|
|
}
|
|
|
|
static UINT32 CalcuFfsSize(EFI_FIRMWARE_VOLUME_HEADER* Fv, CONST EFI_FFS_FILE_HEADER2 *Ffs) {
|
|
EFI_FFS_FILE_HEADER2 *NextFile;
|
|
UINTN FfsSize;
|
|
UINTN FvSize;
|
|
UINTN Offset;
|
|
|
|
FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)Ffs);
|
|
FfsSize += (UINT8 *)ALIGN_POINTER(((UINT8 *)Ffs + FfsSize), 8) - ((UINT8 *)Ffs + FfsSize);
|
|
FvBufGetSize(Fv, &FvSize);
|
|
Offset = (UINT8 *)Ffs - (UINT8 *)Fv;
|
|
if (Offset + FfsSize < FvSize) {
|
|
NextFile = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)Ffs + FfsSize);
|
|
if (NextFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
|
|
FfsSize += GetFfsFileLength((EFI_FFS_FILE_HEADER *)NextFile);
|
|
}
|
|
}
|
|
return FfsSize;
|
|
}
|
|
|
|
static
|
|
EFI_STATUS
|
|
ReadFfsAlignment(
|
|
IN EFI_FFS_FILE_HEADER *FfsFile,
|
|
IN OUT UINT32 *Alignment
|
|
)
|
|
{
|
|
//
|
|
// Verify input parameters.
|
|
//
|
|
if (FfsFile == NULL || Alignment == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch ((FfsFile->Attributes >> 3) & 0x07) {
|
|
|
|
case 0:
|
|
//
|
|
// 1 byte alignment
|
|
//
|
|
*Alignment = 0;
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// 16 byte alignment
|
|
//
|
|
*Alignment = 4;
|
|
break;
|
|
|
|
case 2:
|
|
//
|
|
// 128 byte alignment
|
|
//
|
|
*Alignment = 7;
|
|
break;
|
|
|
|
case 3:
|
|
//
|
|
// 512 byte alignment
|
|
//
|
|
*Alignment = 9;
|
|
break;
|
|
|
|
case 4:
|
|
//
|
|
// 1K byte alignment
|
|
//
|
|
*Alignment = 10;
|
|
break;
|
|
|
|
case 5:
|
|
//
|
|
// 4K byte alignment
|
|
//
|
|
*Alignment = 12;
|
|
break;
|
|
|
|
case 6:
|
|
//
|
|
// 32K byte alignment
|
|
//
|
|
*Alignment = 15;
|
|
break;
|
|
|
|
case 7:
|
|
//
|
|
// 64K byte alignment
|
|
//
|
|
*Alignment = 16;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
ReplaceFfs(EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, EFI_FFS_FILE_HEADER2 *OldFfs) {
|
|
UINT32 FfsSize;
|
|
UINT32 NewFileSize;
|
|
UINT32 Offset;
|
|
UINT32 Align;
|
|
UINT32 HdrSize;
|
|
UINT32 PadSize;
|
|
EFI_FFS_FILE_HEADER2 *Pad;
|
|
|
|
Align = 0;
|
|
PadSize = 0;
|
|
Pad = NULL;
|
|
ReadFfsAlignment((EFI_FFS_FILE_HEADER *)InputFfs, &Align);
|
|
Align = 1 << Align;
|
|
HdrSize = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
|
|
|
|
FfsSize = CalcuFfsSize(Fv, OldFfs);
|
|
//
|
|
// Align data
|
|
//
|
|
if ((((UINT8 *)OldFfs - (UINT8 *)Fv) + HdrSize) % Align != 0) {
|
|
PadSize = ((UINT8 *)OldFfs - (UINT8 *)Fv) + sizeof (EFI_FFS_FILE_HEADER)+HdrSize;
|
|
while (PadSize % Align != 0) {
|
|
PadSize++;
|
|
}
|
|
PadSize -= HdrSize;
|
|
PadSize -= ((UINT8 *)OldFfs - (UINT8 *)Fv);
|
|
if (FfsSize < PadSize) {
|
|
return FALSE;
|
|
}
|
|
FfsSize -= PadSize;
|
|
Pad = OldFfs;
|
|
OldFfs = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + PadSize);
|
|
}
|
|
|
|
NewFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
|
|
Offset = (UINT8 *)ALIGN_POINTER(((UINT8 *)OldFfs + NewFileSize), 8) - ((UINT8 *)OldFfs + NewFileSize);
|
|
if (FfsSize >= NewFileSize && FfsSize - NewFileSize <= 7) {
|
|
memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
|
|
if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
memset((UINT8 *)OldFfs + NewFileSize, -1, FfsSize - NewFileSize);
|
|
}
|
|
else {
|
|
memset((UINT8 *)OldFfs + NewFileSize, 0, FfsSize - NewFileSize);
|
|
}
|
|
}
|
|
else if (FfsSize >= NewFileSize + sizeof(EFI_FFS_FILE_HEADER) + Offset) {
|
|
memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize);
|
|
AddPadFile(
|
|
Fv,
|
|
(EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + NewFileSize + Offset),
|
|
FfsSize - NewFileSize - Offset
|
|
);
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
OldFfs->State = (UINT8)~(InputFfs->State);
|
|
}
|
|
if (PadSize != 0) {
|
|
AddPadFile(Fv, Pad, PadSize);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
|
|
EFI_STATUS
|
|
AddFfs(UINT8 *FdBuffer, UINT32 ImageAddress, EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, UINT32 *OffsetAdded) {
|
|
UINTN FreeOffset;
|
|
UINTN Offset;
|
|
UINTN FfsSize;
|
|
EFI_STATUS Status;
|
|
EFI_FFS_FILE_HEADER2 *CurrentFile;
|
|
EFI_FFS_FILE_HEADER FreeHeader;
|
|
|
|
if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
memset(&FreeHeader, -1, sizeof(EFI_FFS_FILE_HEADER));
|
|
}
|
|
else {
|
|
memset(&FreeHeader, 0, sizeof(EFI_FFS_FILE_HEADER));
|
|
}
|
|
|
|
FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
|
|
|
|
Offset = 0;
|
|
CurrentFile = NULL;
|
|
FreeOffset = 0;
|
|
do {
|
|
if (FreeOffset == 0 && memcmp(FdBuffer + ImageAddress + (UINTN)ALIGN_POINTER(Offset, 8), &FreeHeader, sizeof(EFI_FFS_FILE_HEADER)) == 0) {
|
|
//
|
|
// Offset of free FV space found
|
|
//
|
|
FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8);
|
|
}
|
|
Status = FvBufFindNextFile(FdBuffer + ImageAddress, &Offset, (VOID **)&CurrentFile);
|
|
if (Status == EFI_NOT_FOUND) {
|
|
CurrentFile = NULL;
|
|
break;
|
|
}
|
|
else if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (CurrentFile != NULL && CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD &&
|
|
ReplaceFfs(Fv, InputFfs, CurrentFile)) {
|
|
*OffsetAdded = (UINT8 *)CurrentFile - (FdBuffer + ImageAddress);
|
|
return EFI_SUCCESS;
|
|
}
|
|
} while (CurrentFile != NULL);
|
|
|
|
if (FreeOffset != 0) {
|
|
if (Fv->FvLength - FreeOffset < FfsSize) {
|
|
return EFI_ABORTED;
|
|
}
|
|
if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
InputFfs->State = (UINT8)~(InputFfs->State);
|
|
}
|
|
memcpy(FdBuffer + ImageAddress + FreeOffset, InputFfs, FfsSize);
|
|
*OffsetAdded = FreeOffset;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
static
|
|
EFI_STATUS
|
|
FindPreviousFile(VOID *Fv, VOID *CurrentFile, VOID **PreFile) {
|
|
EFI_STATUS Status;
|
|
VOID *File = NULL;
|
|
UINTN Offset = 0;
|
|
|
|
do {
|
|
*PreFile = File;
|
|
Status = FvBufFindNextFile(Fv, &Offset, &File);
|
|
if (Status == EFI_NOT_FOUND) {
|
|
CurrentFile = NULL;
|
|
break;
|
|
}
|
|
else if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
if (File == CurrentFile) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
} while (CurrentFile != NULL);
|
|
*PreFile = NULL;
|
|
return Status;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
NeedNewPath(FV_INFORMATION *FvInFd, CHAR8 *FvId, UINT32 FileIndex, BOOLEAN IsAdd) {
|
|
UINT32 Index;
|
|
|
|
Index = 0;
|
|
|
|
if (strcmp(FvId, FvInFd->FvName) != 0) {
|
|
return FALSE;
|
|
}
|
|
if (IsAdd) {
|
|
return TRUE;
|
|
}
|
|
if (FvInFd->FfsAttuibutes[FileIndex].FvLevel != 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
|
|
if (FvInFd->FfsAttuibutes[Index].FvLevel != 1) {
|
|
continue;
|
|
}
|
|
switch (FvInFd->FfsHeader[Index].Type) {
|
|
case EFI_FV_FILETYPE_PEI_CORE:
|
|
case EFI_FV_FILETYPE_PEIM:
|
|
case EFI_FV_FILETYPE_SECURITY_CORE:
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static UINT32 FindFile(FV_INFORMATION *FvInFd, UINT8 FvLevel, CHAR8 *File, UINT32 *MatchIndex) {
|
|
UINT32 Index = 0;
|
|
CHAR16 *UIName;
|
|
CHAR16 *FfsUIName;
|
|
UINT32 FileNumber = 0;
|
|
|
|
UIName = (CHAR16 *)malloc(_MAX_PATH);
|
|
if (NULL == UIName) {
|
|
return 0;
|
|
}
|
|
FfsUIName = (CHAR16 *)malloc(_MAX_PATH);
|
|
if (NULL == FfsUIName) {
|
|
free(UIName);
|
|
return 0;
|
|
}
|
|
LibAscii2Unicode(File, UIName);
|
|
for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
|
|
//
|
|
// Compare the New File Name with UI Name of FFS
|
|
// NOTE: The UI Name is Unicode, but the New File Name is Ascii.
|
|
//
|
|
memcpy(FfsUIName, (CHAR16 *)(FvInFd->FfsAttuibutes[Index].UiName), _MAX_PATH);
|
|
|
|
if (FvInFd->FfsAttuibutes[Index].UiNameSize > 0 && memcmp(UIName, FfsUIName, FvInFd->FfsAttuibutes[Index].UiNameSize) == 0) {
|
|
FileNumber += 1;
|
|
*MatchIndex = Index;
|
|
if (FileNumber > 1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
free(UIName);
|
|
free(FfsUIName);
|
|
|
|
return FileNumber;
|
|
}
|
|
|
|
/**
|
|
Search the config file from the path list.
|
|
|
|
Split the path from env PATH, and then search the cofig
|
|
file from these paths. The priority is from left to
|
|
right of PATH string. When met the first Config file, it
|
|
will break and return the pointer to the full file name.
|
|
|
|
@param PathList the pointer to the path list.
|
|
@param FileName the pointer to the file name.
|
|
|
|
@retval The pointer to the file name.
|
|
@return NULL An error occurred.
|
|
**/
|
|
CHAR8 *
|
|
SearchConfigFromPathList (
|
|
IN CHAR8 *PathList,
|
|
IN CHAR8 *FileName
|
|
)
|
|
{
|
|
CHAR8 *CurDir;
|
|
CHAR8 *FileNamePath;
|
|
|
|
CurDir = NULL;
|
|
FileNamePath = NULL;
|
|
|
|
#ifndef __GNUC__
|
|
CurDir = strtok (PathList,";");
|
|
#else
|
|
CurDir = strtok (PathList,":");
|
|
#endif
|
|
while (CurDir != NULL) {
|
|
FileNamePath = (char *)calloc(
|
|
strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
|
|
sizeof(char)
|
|
);
|
|
if (FileNamePath == NULL) {
|
|
return NULL;
|
|
}
|
|
sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
|
|
if (access (FileNamePath, 0) != -1) {
|
|
return FileNamePath;
|
|
}
|
|
#ifndef __GNUC__
|
|
CurDir = strtok(NULL, ";");
|
|
#else
|
|
CurDir = strtok(NULL, ":");
|
|
#endif
|
|
free (FileNamePath);
|
|
FileNamePath = NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UINT32 lenList(FILENode* head){
|
|
FILENode *p = head;
|
|
UINT32 sum=0;
|
|
if(head==NULL) return 0;
|
|
while(p!=NULL){
|
|
sum+=1;
|
|
p=p->Next;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
void sortList(FILENode* head){
|
|
UINT32 len = lenList(head);
|
|
FILENode *p = head;
|
|
UINT32 i;
|
|
UINT32 j;
|
|
if(len==0) return;
|
|
for(i=1; i<len; ++i){
|
|
p = head;
|
|
for(j=0; j<len-i; j++){
|
|
if(p->SubLevel < p->Next->SubLevel){
|
|
CHAR8 *FileName = p->FileName;
|
|
UINT8 tmp = p->SubLevel;
|
|
p->SubLevel = p->Next->SubLevel;
|
|
p->Next->SubLevel = tmp;
|
|
p->FileName = p->Next->FileName;
|
|
p->Next->FileName = FileName;
|
|
}
|
|
p=p->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
ParseSection (
|
|
IN EFI_FFS_FILE_HEADER2 *InputFfs
|
|
)
|
|
{
|
|
BOOLEAN UISectionFlag;
|
|
UINT32 SectionLength;
|
|
UINT32 ParsedLength;
|
|
UINT32 FfsFileSize;
|
|
UINT8 *Ptr;
|
|
EFI_SECTION_TYPE Type;
|
|
|
|
UISectionFlag = FALSE;
|
|
Ptr = NULL;
|
|
SectionLength = 0;
|
|
ParsedLength = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs);
|
|
FfsFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs);
|
|
|
|
while (ParsedLength < FfsFileSize) {
|
|
Ptr = (UINT8 *)InputFfs + ParsedLength;
|
|
SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
|
|
Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
|
|
|
|
//
|
|
// This is sort of an odd check, but is necessary because FFS files are
|
|
// padded to a QWORD boundary, meaning there is potentially a whole section
|
|
// header worth of 0xFF bytes.
|
|
//
|
|
if ((SectionLength == 0xffffff) && (Type == 0xff)) {
|
|
ParsedLength += 4;
|
|
continue;
|
|
}
|
|
if (Type == EFI_SECTION_USER_INTERFACE) {
|
|
UISectionFlag = TRUE;
|
|
break;
|
|
}
|
|
ParsedLength += SectionLength;
|
|
//
|
|
// We make then next section begin on a 4-byte boundary
|
|
//
|
|
ParsedLength = GetOccupiedSize (ParsedLength, 4);
|
|
}
|
|
return UISectionFlag;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Show the FD image layout information. Only display the modules with UI name.
|
|
|
|
@param[in] FdInName Input FD binary/image file name;
|
|
@param[in] FvName The FV ID in the FD file;
|
|
@param[in] ViewFlag Is this call for view or other operate(add/del/replace)
|
|
@param[in] FdData The Fd data structure store the FD information.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_INVALID_PARAMETER
|
|
@retval EFI_ABORTED
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FmmtImageView (
|
|
IN CHAR8* FdInName,
|
|
IN CHAR8* FvName,
|
|
IN BOOLEAN ViewFlag,
|
|
IN FIRMWARE_DEVICE **FdData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS ErrorStatus;
|
|
FIRMWARE_DEVICE *LocalFdData;
|
|
FV_INFORMATION *CurrentFv;
|
|
FILE *InputFile;
|
|
UINT32 FvSize;
|
|
UINTN BytesRead;
|
|
EFI_FIRMWARE_VOLUME_HEADER *FvImage;
|
|
UINT32 FfsCount;
|
|
UINT8 FvCount;
|
|
CHAR8 *TemDir;
|
|
|
|
LocalFdData = NULL;
|
|
CurrentFv = NULL;
|
|
FvImage = NULL;
|
|
TemDir = NULL;
|
|
FvSize = 0;
|
|
BytesRead = 0;
|
|
FfsCount = 0;
|
|
FvCount = 0;
|
|
ErrorStatus = EFI_SUCCESS;
|
|
|
|
//
|
|
// Check the FD file name/path.
|
|
//
|
|
if (FdInName == NULL) {
|
|
Error("FMMT", 0, 1001, "Invalid parameter! Please specify <input-binary-file>", FdInName);
|
|
Usage();
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Open the file containing the FV
|
|
//
|
|
InputFile = fopen (FdInName, "rb");
|
|
if (InputFile == NULL) {
|
|
Error (NULL, 0, 0001, "Error opening the input file", FdInName);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = LibFindFvInFd (InputFile, &LocalFdData);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 1001, "Error while search FV in FD", "");
|
|
fclose (InputFile);
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
CurrentFv = LocalFdData->Fv;
|
|
|
|
|
|
do {
|
|
|
|
memset (CurrentFv->FvName, '\0', _MAX_PATH);
|
|
|
|
if (FvCount == 0) {
|
|
sprintf (CurrentFv->FvName, "FV%d", FvCount);
|
|
} else {
|
|
sprintf (CurrentFv->FvName, "FV%d", FvCount);
|
|
}
|
|
|
|
//
|
|
// Determine size of FV
|
|
//
|
|
if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
|
|
Error (NULL, 0, 0003, "error parsing FV image", "%s FD file is invalid", InputFile);
|
|
fclose (InputFile);
|
|
ErrorStatus = EFI_ABORTED;
|
|
goto Done;
|
|
}
|
|
|
|
Status = LibGetFvSize(InputFile, &FvSize);
|
|
if (EFI_ERROR (Status)) {
|
|
Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", InputFile);
|
|
fclose (InputFile);
|
|
ErrorStatus = EFI_ABORTED;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Seek to the start of the image, then read the entire FV to the buffer
|
|
//
|
|
fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET);
|
|
|
|
|
|
FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize);
|
|
|
|
if (FvImage == NULL) {
|
|
Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
fclose (InputFile);
|
|
ErrorStatus = EFI_ABORTED;
|
|
goto Done;
|
|
}
|
|
|
|
BytesRead = fread (FvImage, 1, FvSize, InputFile);
|
|
if ((unsigned int) BytesRead != FvSize) {
|
|
Error ("FMMT", 0, 0004, "error reading FvImage from", FdInName);
|
|
free (FvImage);
|
|
fclose (InputFile);
|
|
ErrorStatus = EFI_ABORTED;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Collect FV information each by each.
|
|
//
|
|
Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &CurrentFv->EncapData, &FfsCount, &FvCount, ViewFlag, FALSE);
|
|
if (FvImage != NULL) {
|
|
free (FvImage);
|
|
FvImage = NULL;
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0004, "error while get information from FV %s", FvName);
|
|
ErrorStatus = Status;
|
|
//
|
|
// If the FV to be parsed error is the same with the input FV in add, replace and delete
|
|
// operation, abort the program directly.
|
|
//
|
|
if ((FvName != NULL) && ((CurrentFv->FvName) != NULL) && !strcmp(CurrentFv->FvName, FvName)) {
|
|
fclose (InputFile);
|
|
ErrorStatus = EFI_ABORTED;
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
|
|
FfsCount = 0;
|
|
|
|
CurrentFv = CurrentFv->FvNext;
|
|
|
|
} while (CurrentFv != NULL);
|
|
|
|
fclose (InputFile);
|
|
|
|
if (ViewFlag) {
|
|
|
|
TemDir = getcwd (NULL, _MAX_PATH);
|
|
if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
|
|
Error("FMMT", 0, 1001, "The directory is too long.", "");
|
|
ErrorStatus = EFI_ABORTED;
|
|
goto Done;
|
|
}
|
|
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
|
|
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
|
|
|
|
mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
|
|
|
|
Status = LibRmDir (TemDir);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
|
|
ErrorStatus = Status;
|
|
}
|
|
}
|
|
Done:
|
|
if (!ViewFlag) {
|
|
*FdData = LocalFdData;
|
|
} else {
|
|
LibFmmtFreeFd( LocalFdData);
|
|
}
|
|
return ErrorStatus;
|
|
}
|
|
|
|
/**
|
|
Add FFS file into a specify FV.
|
|
|
|
@param[in] FdInName Input FD binary/image file name;
|
|
@param[in] FileList The FV ID and FFS file Data;
|
|
@param[in] count The length of FileList;
|
|
@param[in] FdOutName Name of output FD binary/image file.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_INVALID_PARAMETER
|
|
@retval EFI_ABORTED
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FmmtImageAdd(
|
|
IN CHAR8* FdInName,
|
|
IN Data *FileList,
|
|
IN int count,
|
|
IN CHAR8* FdOutName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
FIRMWARE_DEVICE *FdData;
|
|
FV_INFORMATION *FvInFd;
|
|
FILE* NewFdFile;
|
|
FILE* NewFvFile;
|
|
UINT64 NewFvLength;
|
|
VOID* Buffer;
|
|
CHAR8 *TemDir;
|
|
UINT8 FvNumInFd;
|
|
UINT8 FvNumInFdCounter;
|
|
UINT8 NewAddedFfsLevel;
|
|
FFS_INFORMATION *OutputFileName;
|
|
UINT32 Index;
|
|
UINT32 EndId;
|
|
UINT8 *FdBuffer;
|
|
EFI_FIRMWARE_VOLUME_HEADER *Fv;
|
|
UINT32 FdSize;
|
|
EFI_FFS_FILE_HEADER2 *InputFfs;
|
|
UINT32 NewFileSize;
|
|
UINT64 BaseAddr;
|
|
UINT32 OffsetAdded;
|
|
int i;
|
|
int j;
|
|
Data *tmp;
|
|
CHAR8* FvId;
|
|
CHAR8* NewFile;
|
|
FILENode *NewFileNode;
|
|
BOOLEAN HasUISection;
|
|
HasUISection = FALSE;
|
|
Index = 0;
|
|
EndId = 0;
|
|
NewFvLength = 0;
|
|
FvNumInFd = 0;
|
|
FvNumInFdCounter = 0;
|
|
NewAddedFfsLevel = 0;
|
|
FdData = NULL;
|
|
FvInFd = NULL;
|
|
NewFdFile = NULL;
|
|
NewFvFile = NULL;
|
|
Buffer = NULL;
|
|
TemDir = NULL;
|
|
OutputFileName = NULL;
|
|
FvId = NULL;
|
|
NewFile = NULL;
|
|
|
|
FdBuffer = NULL;
|
|
InputFfs = NULL;
|
|
BaseAddr = 0;
|
|
OffsetAdded = 0;
|
|
FdSize = 0;
|
|
|
|
for (i = 0; i < count; i ++){
|
|
tmp = FileList + i;
|
|
FvId = tmp->FvId;
|
|
FdData = tmp->FdData;
|
|
if (FdData == NULL) {
|
|
Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
|
|
if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
|
|
Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
|
|
return Status;
|
|
}
|
|
if (FdData == NULL) {
|
|
Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
|
|
return Status;
|
|
}
|
|
(FileList + i) -> FdData = FdData;
|
|
(FileList + i) -> FvInFd = FvInFd;
|
|
(FileList + i) -> FvLevel = FvInFd -> FvLevel;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
for (j = i + 1; j < count; j++){
|
|
if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
|
|
continue;
|
|
}
|
|
if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
|
|
NewFileNode = (FileList + j)->NewFile;
|
|
while (NewFileNode ->Next != NULL) {
|
|
NewFileNode = NewFileNode->Next;
|
|
}
|
|
NewFileNode->Next = (FileList + i)->NewFile;
|
|
(FileList + i)->FvId = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i ++){
|
|
if ((FileList + i)->FvId == NULL) {
|
|
continue;
|
|
}
|
|
sortList ((FileList + i)-> NewFile);
|
|
}
|
|
|
|
TemDir = getcwd(NULL, _MAX_PATH);
|
|
if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
|
|
Error("FMMT", 0, 1001, "The directory is too long.", "");
|
|
return EFI_ABORTED;
|
|
}
|
|
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
|
|
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
|
|
|
|
if (FdBuffer == NULL) {
|
|
FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
|
|
if (FdBuffer == NULL) {
|
|
Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
|
|
return EFI_ABORTED;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i ++){
|
|
tmp = FileList + i;
|
|
FvId = tmp->FvId;
|
|
if (FvId == NULL) {
|
|
continue;
|
|
}
|
|
FdData = tmp->FdData;
|
|
FvInFd = tmp->FvInFd;
|
|
NewFileNode =tmp->NewFile;
|
|
|
|
NewFile = NewFileNode->FileName;
|
|
InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
|
|
if (InputFfs == NULL) {
|
|
Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
HasUISection = FALSE;
|
|
HasUISection = ParseSection(InputFfs);
|
|
if (!HasUISection) {
|
|
printf ("WARNING: The newly add file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
|
|
}
|
|
if (NeedNewPath(FvInFd, FvId, 0, TRUE)) {
|
|
do {
|
|
NewFile = NewFileNode->FileName;
|
|
//
|
|
// TODO: currently only root FV is handled
|
|
//
|
|
InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
|
|
if (InputFfs == NULL) {
|
|
Error("FMMT", 0, 0004, "error while adding file", "cannot read input file.");
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
|
|
Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
|
|
|
|
Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0003, "error while adding file", "Not enough space to add FFS");
|
|
goto FAILED;
|
|
}
|
|
//
|
|
// Calculate base address of Current FV
|
|
//
|
|
if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
|
|
Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
|
|
if (!EFI_ERROR(Status)) {
|
|
mFvHeader = FvInFd->FvHeader;
|
|
mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
|
|
RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
|
|
}
|
|
else {
|
|
Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
|
|
if (!EFI_ERROR(Status)) {
|
|
mFvHeader = FvInFd->FvHeader;
|
|
mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
|
|
RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
|
|
}
|
|
}
|
|
}
|
|
NewFileNode = NewFileNode->Next;
|
|
free (InputFfs);
|
|
InputFfs = NULL;
|
|
} while (NewFileNode != NULL);
|
|
} else {
|
|
do {
|
|
NewFile = NewFileNode->FileName;
|
|
if (strlen (NewFile) > _MAX_PATH - 1) {
|
|
Error ("FMMT", 0, 2000, "error while adding file", "New file name is too long!");
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2));
|
|
if (FvInFd->FfsNumbers == 0) {
|
|
NewAddedFfsLevel = FvInFd->FfsAttuibutes[0].Level;
|
|
}
|
|
for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
|
|
if (FvInFd->FfsAttuibutes[Index].IsFvStart == 1) {
|
|
FvNumInFdCounter++;
|
|
}
|
|
if ( FvNumInFdCounter == FvNumInFd && FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
|
|
NewAddedFfsLevel = FvInFd->FfsAttuibutes[Index].Level;
|
|
EndId = Index+1;
|
|
break;
|
|
}
|
|
if (FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) {
|
|
FvNumInFdCounter--;
|
|
if (FvNumInFdCounter == 0) {
|
|
FvNumInFd--;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the new file into FV.
|
|
//
|
|
FvInFd->FfsNumbers += 1;
|
|
for (Index = FvInFd->FfsNumbers; Index > EndId; Index--) {
|
|
FvInFd->FfsAttuibutes[Index] = FvInFd->FfsAttuibutes[Index - 1];
|
|
}
|
|
strncpy(FvInFd->FfsAttuibutes[EndId].FfsName, NewFile, _MAX_PATH - 1);
|
|
FvInFd->FfsAttuibutes[EndId].FfsName[_MAX_PATH - 1] = 0;
|
|
FvInFd->FfsAttuibutes[EndId].Level = NewAddedFfsLevel;
|
|
memset (&FvInFd->FfsAttuibutes[EndId].GuidName, '\0', sizeof(EFI_GUID));
|
|
if (EndId > 0) {
|
|
FvInFd->FfsAttuibutes[EndId].FvLevel = FvInFd->FfsAttuibutes[EndId - 1].FvLevel;
|
|
FvInFd->FfsAttuibutes[EndId - 1].IsFvEnd = 0;
|
|
}
|
|
FvInFd->FfsAttuibutes[EndId].IsFvEnd = 1;
|
|
FvInFd->FfsAttuibutes[EndId].IsFvStart = 0;
|
|
NewFileNode = NewFileNode->Next;
|
|
} while (NewFileNode != NULL);
|
|
|
|
mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
|
|
|
|
Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
|
|
goto FAILED;
|
|
}
|
|
|
|
NewFvFile = fopen (OutputFileName->FFSName, "rb+");
|
|
if (NewFvFile == NULL) {
|
|
Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
|
|
fseek(NewFvFile,0,SEEK_SET);
|
|
fseek(NewFvFile,0,SEEK_END);
|
|
|
|
NewFvLength = ftell(NewFvFile);
|
|
fseek(NewFvFile,0,SEEK_SET);
|
|
Buffer = malloc ((size_t)NewFvLength);
|
|
if (Buffer == NULL) {
|
|
Status = EFI_ABORTED;
|
|
fclose(NewFvFile);
|
|
goto FAILED;
|
|
}
|
|
|
|
if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
|
|
Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
|
|
free (Buffer);
|
|
Status = EFI_ABORTED;
|
|
fclose(NewFvFile);
|
|
goto FAILED;
|
|
}
|
|
|
|
if (NewFvLength <= FvInFd->FvHeader->FvLength) {
|
|
memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
|
|
} else {
|
|
Error ("FMMT", 0, 0004, "error writing FD file", "The add ffs file is too large.");
|
|
}
|
|
fclose(NewFvFile);
|
|
free(Buffer);
|
|
}
|
|
}
|
|
|
|
Status = LibRmDir(TemDir);
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
|
|
goto FAILED;
|
|
}
|
|
|
|
NewFdFile = fopen(FdOutName, "wb");
|
|
if (NewFdFile == NULL) {
|
|
Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
|
|
fwrite(FdBuffer, 1, FdSize, NewFdFile);
|
|
fclose(NewFdFile);
|
|
free(FdBuffer);
|
|
free(InputFfs);
|
|
printf ("Create New FD file successfully. \n\nDone! \n");
|
|
return EFI_SUCCESS;
|
|
|
|
FAILED:
|
|
if (FdBuffer != NULL) {
|
|
free(FdBuffer);
|
|
}
|
|
if (InputFfs != NULL) {
|
|
free(InputFfs);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Delete a root FV from FD.
|
|
|
|
@param[in] FdInName Input FD binary/image file name;
|
|
@param[in] FvName FV name;
|
|
@param[in] FdOutName Name of output fd file.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_INVALID_PARAMETER
|
|
@retval EFI_ABORTED
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FmmtImageDeleteFv(
|
|
IN CHAR8* FdInName,
|
|
IN CHAR8* FvName,
|
|
IN CHAR8* FdOutName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
FV_INFORMATION *FvInFd;
|
|
FILE *NewFdFile;
|
|
CHAR8 *TemDir;
|
|
|
|
UINT8 *FdBuffer = NULL;
|
|
UINT8 *FdBak = NULL;
|
|
UINT32 FdSize = 0;
|
|
|
|
FIRMWARE_DEVICE *FdData = NULL;
|
|
|
|
TemDir = getcwd(NULL, _MAX_PATH);
|
|
if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
|
|
Error("FMMT", 0, 1001, "The directory is too long.", "");
|
|
return EFI_ABORTED;
|
|
}
|
|
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
|
|
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
|
|
|
|
Status = FmmtImageView(FdInName, NULL, FALSE, &FdData);
|
|
if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
|
|
Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
|
|
goto END;
|
|
}
|
|
if (FdData == NULL) {
|
|
Error("FMMT", 0, 0004, "error while parsing FD Image", "");
|
|
Status = EFI_ABORTED;
|
|
goto END;
|
|
}
|
|
|
|
FvInFd = FdData->Fv;
|
|
while (FvInFd) {
|
|
if (FvInFd->FvUiName && strcmp(FvInFd->FvUiName, FvName) == 0) {
|
|
break;
|
|
}
|
|
FvInFd = FvInFd->FvNext;
|
|
}
|
|
if (!FvInFd) {
|
|
Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot find this FV!");
|
|
Status = EFI_ABORTED;
|
|
goto END;
|
|
}
|
|
FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
|
|
FdBak = FdBuffer;
|
|
if (FdBuffer == NULL) {
|
|
Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot read FD file!");
|
|
Status = EFI_ABORTED;
|
|
goto END;
|
|
}
|
|
|
|
if (FvInFd->ImageAddress == 0) {
|
|
FdBuffer = FdBuffer + FvInFd->FvHeader->FvLength;
|
|
FdSize -= (UINT32)FvInFd->FvHeader->FvLength;
|
|
} else {
|
|
if (FvInFd->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
memset(FdBuffer + FvInFd->ImageAddress, -1, (size_t)FvInFd->FvHeader->FvLength);
|
|
}
|
|
else {
|
|
memset(FdBuffer + FvInFd->ImageAddress, 0, (size_t)FvInFd->FvHeader->FvLength);
|
|
}
|
|
}
|
|
|
|
NewFdFile = fopen(FdOutName, "wb");
|
|
if (NewFdFile == NULL) {
|
|
Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot open target FD file!");
|
|
Status = EFI_ABORTED;
|
|
goto END;
|
|
}
|
|
fwrite(FdBuffer, 1, FdSize, NewFdFile);
|
|
fclose(NewFdFile);
|
|
|
|
Status = LibRmDir(TemDir);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0004, "error while deleting root FV", "remove directory failed!");
|
|
goto END;
|
|
}
|
|
|
|
printf("Create New FD file successfully. \n\nDone! \n");
|
|
END:
|
|
LibFmmtFreeFd(FdData);
|
|
free(FdBak);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Delete an FFS file from a specify FV.
|
|
|
|
@param[in] FdInName Input FD binary/image file name;
|
|
@param[in] FileList The FV ID and FFS file Data;
|
|
@param[in] count The length of FileList;
|
|
@param[in] FdOutName Name of output fd file.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_INVALID_PARAMETER
|
|
@retval EFI_ABORTED
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FmmtImageDelete (
|
|
IN CHAR8* FdInName,
|
|
IN Data *FileList,
|
|
IN int count,
|
|
IN CHAR8* FdOutName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
FIRMWARE_DEVICE *FdData;
|
|
FV_INFORMATION *FvInFd;
|
|
UINT32 Index;
|
|
UINT32 FfsFoundFlag;
|
|
FFS_INFORMATION *OutputFileName;
|
|
FILE* NewFdFile;
|
|
FILE* NewFvFile;
|
|
UINT64 NewFvLength;
|
|
VOID* Buffer;
|
|
CHAR8 *TemDir;
|
|
UINT8 FvNumInFd;
|
|
UINT32 Offset;
|
|
UINT8 *FdBuffer;
|
|
EFI_FFS_FILE_HEADER2 *CurrentFile;
|
|
EFI_FFS_FILE_HEADER2 *PreFile;
|
|
Data *tmp;
|
|
CHAR8* FvId;
|
|
CHAR8* DelFile;
|
|
FILENode *OldFileNode;
|
|
int i;
|
|
UINT32 FfsSize;
|
|
UINT32 FdSize;
|
|
int j;
|
|
|
|
FdSize = 0;
|
|
Index = 0;
|
|
NewFvLength = 0;
|
|
FfsFoundFlag = 0;
|
|
FdData = NULL;
|
|
FvInFd = NULL;
|
|
OutputFileName = NULL;
|
|
NewFdFile = NULL;
|
|
NewFvFile = NULL;
|
|
Buffer = NULL;
|
|
TemDir = NULL;
|
|
FvNumInFd = 0;
|
|
Offset = 0;
|
|
FdBuffer = NULL;
|
|
|
|
for (i = 0; i < count; i ++){
|
|
tmp = FileList + i;
|
|
FvId = tmp->FvId;
|
|
FdData = tmp->FdData;
|
|
if (FdData == NULL) {
|
|
Status = FmmtImageView (FdInName, FvId, FALSE, &FdData);
|
|
if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
|
|
Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!");
|
|
return Status;
|
|
}
|
|
if (FdData == NULL) {
|
|
Error ("FMMT", 0, 0004, "error while parsing FD Image", "");
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd);
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0005, "error while locate FV in FD", "");
|
|
return Status;
|
|
}
|
|
(FileList + i) -> FdData = FdData;
|
|
(FileList + i) -> FvInFd = FvInFd;
|
|
(FileList + i) -> FvLevel = FvInFd -> FvLevel;
|
|
}
|
|
FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
|
|
OldFileNode = tmp-> OldFile;
|
|
do {
|
|
DelFile = OldFileNode->FileName;
|
|
if (FvInFd == NULL) {
|
|
break;
|
|
}
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
|
|
if (FfsFoundFlag) {
|
|
if (FfsFoundFlag > 1) {
|
|
printf("Duplicated file found in this FV, file name: %s\n", DelFile);
|
|
return EFI_ABORTED;
|
|
}
|
|
} else {
|
|
printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
|
|
return EFI_ABORTED;
|
|
}
|
|
OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
|
|
OldFileNode = OldFileNode->Next;
|
|
} while (OldFileNode != NULL);
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
for (j = i + 1; j < count; j++)
|
|
{
|
|
if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
|
|
continue;
|
|
}
|
|
if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
|
|
OldFileNode = (FileList + j)->OldFile;
|
|
while (OldFileNode ->Next != NULL) {
|
|
OldFileNode = OldFileNode->Next;
|
|
}
|
|
OldFileNode->Next = (FileList + i)->OldFile;
|
|
(FileList + i)->FvId = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i ++){
|
|
if ((FileList + i)->FvId == NULL) {
|
|
continue;
|
|
}
|
|
sortList ((FileList + i)-> OldFile);
|
|
}
|
|
|
|
TemDir = getcwd(NULL, _MAX_PATH);
|
|
if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
|
|
Error("FMMT", 0, 1001, "The directory is too long.", "");
|
|
return EFI_ABORTED;
|
|
}
|
|
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
|
|
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
|
|
|
|
if (FdBuffer == NULL) {
|
|
FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
|
|
if (FdBuffer == NULL) {
|
|
Error("FMMT", 0, 0004, "error while deleting file", "cannot read input file.");
|
|
return EFI_ABORTED;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i ++){
|
|
tmp = FileList + i;
|
|
FvId = tmp->FvId;
|
|
if (FvId == NULL) {
|
|
continue;
|
|
}
|
|
FdData = tmp->FdData;
|
|
FvInFd = tmp->FvInFd;
|
|
FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
|
|
OldFileNode = tmp->OldFile;
|
|
DelFile = OldFileNode -> FileName;
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
|
|
if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
|
|
do {
|
|
DelFile = OldFileNode -> FileName;
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
|
|
//
|
|
// TODO: currently only root FV is handled
|
|
//
|
|
Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
|
|
if (FdBuffer != NULL) {
|
|
CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset);
|
|
|
|
FfsSize = CalcuFfsSize((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile);
|
|
|
|
FindPreviousFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, (VOID **) &PreFile);
|
|
if (PreFile != NULL && PreFile->Type == EFI_FV_FILETYPE_FFS_PAD) {
|
|
FfsSize += (UINT8 *)CurrentFile - (UINT8 *)PreFile;
|
|
CurrentFile = PreFile;
|
|
}
|
|
AddPadFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, FfsSize);
|
|
}
|
|
OldFileNode = OldFileNode -> Next;
|
|
} while (OldFileNode != NULL);
|
|
} else {
|
|
do {
|
|
DelFile = OldFileNode -> FileName;
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index);
|
|
|
|
if (FfsFoundFlag) {
|
|
//
|
|
// Delete this FFS file from Current FV structure.
|
|
//
|
|
Status = LibFmmtDeleteFile (FvInFd->FfsAttuibutes[Index].FfsName);
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
|
|
Error ("FMMT", 0, 0004, "Cannot find the file need to delete", "Please check the name of the file you want to delete!");
|
|
goto FAILED;
|
|
}
|
|
|
|
memset(FvInFd->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH);
|
|
FvInFd->FfsAttuibutes[Index].Level = 0xFF;
|
|
|
|
//
|
|
// Since we can avoid to add NULL ffs file, at this time we don't need to decrease the FFS number.
|
|
// If decrease operation executed, we should adjust the ffs list. It will bring in more complex.
|
|
//
|
|
//FvInFd->FfsNumbers -= 1;
|
|
memset(FvInFd->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH);
|
|
if (FvInFd->FfsAttuibutes[Index].FvLevel > 1) {
|
|
for (j = Index - 1; j >= 0; j--) {
|
|
if (FvInFd->FfsAttuibutes[j].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel - 1) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index+1 <= FvInFd->FfsNumbers) {
|
|
if (FvInFd->FfsAttuibutes[Index+1].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel + 1) {
|
|
for (j = Index+1; j <= (signed)FvInFd->FfsNumbers; j++) {
|
|
if (FvInFd->FfsAttuibutes[j].FvLevel > FvInFd->FfsAttuibutes[Index].FvLevel) {
|
|
Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[j].FfsName);
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!");
|
|
return Status;
|
|
}
|
|
memset(FvInFd->FfsAttuibutes[j].FfsName, '\0', _MAX_PATH);
|
|
FvInFd->FfsAttuibutes[j].Level = 0xFF;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile);
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
OldFileNode = OldFileNode -> Next;
|
|
|
|
}while (OldFileNode != NULL);
|
|
|
|
mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
|
|
|
|
Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
|
|
goto FAILED;
|
|
}
|
|
|
|
NewFvFile = fopen (OutputFileName->FFSName, "rb+");
|
|
if (NewFvFile == NULL) {
|
|
Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
|
|
fseek(NewFvFile,0,SEEK_SET);
|
|
fseek(NewFvFile,0,SEEK_END);
|
|
|
|
NewFvLength = ftell(NewFvFile);
|
|
fseek(NewFvFile,0,SEEK_SET);
|
|
Buffer = malloc ((size_t)NewFvLength);
|
|
if (Buffer == NULL) {
|
|
fclose(NewFvFile);
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
|
|
if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
|
|
Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
|
|
fclose(NewFvFile);
|
|
free(Buffer);
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
|
|
free(Buffer);
|
|
fclose(NewFvFile);
|
|
}
|
|
}
|
|
|
|
Status = LibRmDir(TemDir);
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
|
|
goto FAILED;
|
|
}
|
|
|
|
NewFdFile = fopen(FdOutName, "wb");
|
|
if (NewFdFile == NULL) {
|
|
Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!");
|
|
Status = EFI_ABORTED;
|
|
goto FAILED;
|
|
}
|
|
|
|
fwrite(FdBuffer, 1, FdSize, NewFdFile);
|
|
fclose(NewFdFile);
|
|
free(FdBuffer);
|
|
printf("Create New FD file successfully. \n\nDone! \n");
|
|
return EFI_SUCCESS;
|
|
|
|
FAILED:
|
|
free(FdBuffer);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Replace the exist FFS file with new one from a specify FV.
|
|
|
|
@param[in] FdInName Input FD binary/image file name;
|
|
@param[in] FileList The FV ID and FFS file Data;
|
|
@param[in] count The length of FileList;
|
|
@param[in] FdOutName Name of output fd file.
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_INVALID_PARAMETER
|
|
@retval EFI_ABORTED
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FmmtImageReplace (
|
|
IN CHAR8* FdInName,
|
|
IN Data *FileList,
|
|
IN int count,
|
|
IN CHAR8* FdOutName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
FIRMWARE_DEVICE *FdData;
|
|
FV_INFORMATION *FvInFd;
|
|
UINT32 Index;
|
|
UINT32 FfsFoundFlag;
|
|
FFS_INFORMATION *OutputFileName;
|
|
FILE* NewFdFile;
|
|
FILE* NewFvFile;
|
|
UINT64 NewFvLength;
|
|
VOID* Buffer;
|
|
CHAR8 *TemDir;
|
|
UINT32 Offset;
|
|
UINT8 *FdBuffer;
|
|
UINT8 FvNumInFd;
|
|
EFI_FFS_FILE_HEADER2 *CurrentFile;
|
|
EFI_FIRMWARE_VOLUME_HEADER *Fv;
|
|
UINT32 FdSize;
|
|
EFI_FFS_FILE_HEADER2 *InputFfs;
|
|
UINT32 NewFileSize;
|
|
UINT32 PadFileSize;
|
|
UINT64 BaseAddr;
|
|
UINT32 OffsetAdded;
|
|
Data *tmp;
|
|
CHAR8* FvId;
|
|
CHAR8* OldFile;
|
|
CHAR8* NewFile;
|
|
int i;
|
|
int j;
|
|
FILENode *OldFileNode;
|
|
FILENode *NewFileNode;
|
|
BOOLEAN HasUISection;
|
|
HasUISection = FALSE;
|
|
Index = 0;
|
|
NewFvLength = 0;
|
|
FfsFoundFlag = 0;
|
|
FdData = NULL;
|
|
FvInFd = NULL;
|
|
OutputFileName = NULL;
|
|
NewFdFile = NULL;
|
|
NewFvFile = NULL;
|
|
Buffer = NULL;
|
|
TemDir = NULL;
|
|
Offset = 0;
|
|
FdBuffer = NULL;
|
|
InputFfs = NULL;
|
|
BaseAddr = 0;
|
|
OffsetAdded = 0;
|
|
FdSize = 0;
|
|
|
|
for (i = 0; i < count; i ++){
|
|
tmp = FileList + i;
|
|
FvId = tmp->FvId;
|
|
FdData = tmp->FdData;
|
|
if (FdData == NULL){
|
|
Status = FmmtImageView(FdInName, FvId, FALSE, &FdData);
|
|
if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) {
|
|
Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
|
|
return Status;
|
|
}
|
|
|
|
if (FdData == NULL) {
|
|
Error("FMMT", 0, 0004, "error while parsing FD Image", "");
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd);
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0005, "error while locate FV in FD", "");
|
|
return Status;
|
|
}
|
|
(FileList + i) -> FdData = FdData;
|
|
(FileList + i) -> FvInFd = FvInFd;
|
|
(FileList + i) -> FvLevel = FvInFd -> FvLevel;
|
|
}
|
|
FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
|
|
OldFileNode = tmp-> OldFile;
|
|
NewFileNode = tmp-> NewFile;
|
|
do {
|
|
OldFile = OldFileNode -> FileName;
|
|
NewFile = NewFileNode -> FileName;
|
|
if (FvInFd == NULL) {
|
|
break;
|
|
}
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
|
|
|
|
if (FfsFoundFlag) {
|
|
if (FfsFoundFlag > 1) {
|
|
printf("Duplicated file found in this FV, file name: %s\n", OldFile);
|
|
return EFI_ABORTED;
|
|
}
|
|
//
|
|
// Replace this FFS file with the new one.
|
|
// strcpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile);
|
|
} else {
|
|
printf ("Could not found the FFS file need to be replaced from FD! file name: %s\n", OldFile);
|
|
return EFI_ABORTED;
|
|
}
|
|
OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
|
|
NewFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level;
|
|
OldFileNode = OldFileNode->Next;
|
|
NewFileNode = NewFileNode->Next;
|
|
} while (OldFileNode != NULL && NewFileNode != NULL);
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
for (j = i + 1; j < count; j++)
|
|
{
|
|
if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) {
|
|
continue;
|
|
}
|
|
if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){
|
|
OldFileNode = (FileList + j)->OldFile;
|
|
NewFileNode = (FileList + j)->NewFile;
|
|
while (OldFileNode->Next != NULL && NewFileNode->Next != NULL) {
|
|
OldFileNode = OldFileNode->Next;
|
|
NewFileNode = NewFileNode->Next;
|
|
}
|
|
OldFileNode->Next = (FileList + i)->OldFile;
|
|
NewFileNode->Next = (FileList + i)->NewFile;
|
|
(FileList + i)->FvId = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i ++){
|
|
if ((FileList + i)->FvId == NULL) {
|
|
continue;
|
|
}
|
|
sortList ((FileList + i)-> OldFile);
|
|
sortList ((FileList + i)-> NewFile);
|
|
}
|
|
TemDir = getcwd (NULL, _MAX_PATH);
|
|
if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
|
|
Error("FMMT", 0, 1001, "The directory is too long.", "");
|
|
return EFI_ABORTED;
|
|
}
|
|
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
|
|
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
|
|
mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
|
|
if (FdBuffer == NULL) {
|
|
FdBuffer = ReadFileToBuffer(FdInName, &FdSize);
|
|
if (FdBuffer == NULL) {
|
|
Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
|
|
return EFI_ABORTED;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < count; i ++){
|
|
tmp = FileList + i;
|
|
FvId = tmp->FvId;
|
|
if (FvId == NULL) {
|
|
continue;
|
|
}
|
|
FdData = tmp->FdData;
|
|
FvInFd = tmp->FvInFd;
|
|
FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1;
|
|
OldFileNode = tmp-> OldFile;
|
|
OldFile = OldFileNode -> FileName;
|
|
NewFileNode = tmp-> NewFile;
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
|
|
|
|
NewFile = NewFileNode->FileName;
|
|
InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
|
|
if (InputFfs == NULL) {
|
|
Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
|
|
free (FdBuffer);
|
|
return EFI_ABORTED;
|
|
}
|
|
HasUISection = FALSE;
|
|
HasUISection = ParseSection(InputFfs);
|
|
if (!HasUISection) {
|
|
printf ("WARNING: The newly replace file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n");
|
|
}
|
|
if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) {
|
|
do {
|
|
OldFile = OldFileNode -> FileName;
|
|
NewFile = NewFileNode -> FileName;
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
|
|
//
|
|
// TODO: currently only root FV is handled
|
|
//
|
|
InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize);
|
|
if (InputFfs == NULL) {
|
|
Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file.");
|
|
free (FdBuffer);
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset;
|
|
Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress);
|
|
OffsetAdded = FvInFd->FfsAttuibutes[Index].Offset;
|
|
|
|
if (!ReplaceFfs(Fv, InputFfs, (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset))) {
|
|
Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded);
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0003, "error while replacing file", "cannot add ffs");
|
|
goto END;
|
|
}
|
|
//
|
|
// Set original FFS to PAD file
|
|
//
|
|
CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset);
|
|
PadFileSize = CalcuFfsSize(Fv, CurrentFile);
|
|
AddPadFile(Fv, CurrentFile, PadFileSize);
|
|
}
|
|
|
|
//
|
|
// Calculate base address of Current FV
|
|
//
|
|
if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
|
|
Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr);
|
|
if (!EFI_ERROR(Status)) {
|
|
mFvHeader = FvInFd->FvHeader;
|
|
mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
|
|
RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
|
|
}
|
|
else {
|
|
Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr);
|
|
if (!EFI_ERROR(Status)) {
|
|
mFvHeader = FvInFd->FvHeader;
|
|
mFvLength = (UINT32)FvInFd->FvHeader->FvLength;
|
|
RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded);
|
|
}
|
|
}
|
|
}
|
|
OldFileNode = OldFileNode -> Next;
|
|
NewFileNode = NewFileNode -> Next;
|
|
free (InputFfs);
|
|
InputFfs = NULL;
|
|
} while (OldFileNode != NULL && NewFileNode!= NULL);
|
|
} else {
|
|
do {
|
|
OldFile = OldFileNode->FileName;
|
|
NewFile = NewFileNode->FileName;
|
|
FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index);
|
|
//
|
|
// Replace this FFS file with the new one.
|
|
//
|
|
if (strlen (NewFile) > _MAX_PATH - 1) {
|
|
Error ("FMMT", 0, 2000, "error while replacing file", "New file name is too long!");
|
|
free (FdBuffer);
|
|
return EFI_ABORTED;
|
|
}
|
|
strncpy(FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
|
|
FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
|
|
OldFileNode = OldFileNode->Next;
|
|
NewFileNode = NewFileNode->Next;
|
|
} while (OldFileNode != NULL && NewFileNode != NULL);
|
|
Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName);
|
|
if (EFI_ERROR (Status)) {
|
|
Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!");
|
|
free (FdBuffer);
|
|
return Status;
|
|
}
|
|
|
|
NewFvFile = fopen (OutputFileName->FFSName, "rb+");
|
|
if (NewFvFile == NULL) {
|
|
Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file.");
|
|
free (FdBuffer);
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
fseek(NewFvFile,0,SEEK_SET);
|
|
fseek(NewFvFile,0,SEEK_END);
|
|
|
|
NewFvLength = ftell(NewFvFile);
|
|
fseek(NewFvFile,0,SEEK_SET);
|
|
Buffer = malloc ((size_t)NewFvLength);
|
|
if (Buffer == NULL) {
|
|
fclose(NewFvFile);
|
|
free (FdBuffer);
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
|
|
Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName);
|
|
free(Buffer);
|
|
free (FdBuffer);
|
|
fclose(NewFvFile);
|
|
return EFI_ABORTED;
|
|
}
|
|
if (NewFvLength <= FvInFd->FvHeader->FvLength) {
|
|
memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength);
|
|
}else {
|
|
Error ("FMMT", 0, 0004, "error writing FD file", "The replace ffs file is too large.");
|
|
}
|
|
free(Buffer);
|
|
fclose(NewFvFile);
|
|
}
|
|
}
|
|
|
|
Status = LibRmDir(TemDir);
|
|
if (EFI_ERROR(Status)) {
|
|
Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!");
|
|
}
|
|
|
|
NewFdFile = fopen(FdOutName, "wb");
|
|
if (NewFdFile == NULL) {
|
|
Error("FMMT", 0, 0004, "error while replacing file", "Cannot open target FD file!");
|
|
Status = EFI_ABORTED;
|
|
goto END;
|
|
}
|
|
fwrite(FdBuffer, 1, FdSize, NewFdFile);
|
|
fclose(NewFdFile);
|
|
free(FdBuffer);
|
|
printf("Create New FD file successfully. \n\nDone! \n");
|
|
return EFI_SUCCESS;
|
|
|
|
END:
|
|
if (FdBuffer != NULL) {
|
|
free(FdBuffer);
|
|
}
|
|
if (InputFfs != NULL) {
|
|
free(InputFfs);
|
|
}
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
/**
|
|
|
|
The main entry of FMMT.
|
|
|
|
@param argc The number of input parameters.
|
|
@param *argv[] The array pointer to the parameters.
|
|
|
|
@retval 0 The application exited normally.
|
|
@retval 1 An error occurred.
|
|
|
|
**/
|
|
int main(
|
|
int Argc,
|
|
char *Argv[]
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR8 *TemDir;
|
|
FILE *CheckFileExist;
|
|
CHAR8 *InFilePath;
|
|
CHAR8 FullGuidToolDefinition[_MAX_PATH];
|
|
CHAR8 *FileName;
|
|
UINTN FileNameIndex;
|
|
CHAR8 *PathList;
|
|
UINTN EnvLen;
|
|
CHAR8 *NewPathList;
|
|
Data *FileData;
|
|
int index;
|
|
int count;
|
|
int exist;
|
|
int j;
|
|
FILENode *p;
|
|
FILENode *q;
|
|
|
|
p = NULL;
|
|
q = NULL;
|
|
TemDir = NULL;
|
|
CheckFileExist = NULL;
|
|
PathList = NULL;
|
|
NewPathList = NULL;
|
|
EnvLen = 0;
|
|
count = 0;
|
|
exist = -1;
|
|
|
|
TemDir = getcwd (NULL, _MAX_PATH);
|
|
if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
|
|
Error("FMMT", 0, 1001, "The directory is too long.", "");
|
|
return 1;
|
|
}
|
|
strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1);
|
|
strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1);
|
|
|
|
//
|
|
// Print utility header
|
|
//
|
|
printf ("Intel(R) %s. Version %d.%d, %s. %s.\n",
|
|
UTILITY_NAME,
|
|
UTILITY_MAJOR_VERSION,
|
|
UTILITY_MINOR_VERSION,
|
|
__DATE__,
|
|
__BUILD_VERSION
|
|
);
|
|
|
|
//
|
|
// Should have more than 1 arguments.
|
|
//
|
|
if (Argc <= 1) {
|
|
Usage();
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Workaroud: the first call to this function
|
|
// returns a file name ends with dot
|
|
//
|
|
#ifndef __GNUC__
|
|
tmpnam (NULL);
|
|
#else
|
|
CHAR8 tmp[] = "/tmp/fileXXXXXX";
|
|
UINTN Fdtmp;
|
|
Fdtmp = mkstemp(tmp);
|
|
close(Fdtmp);
|
|
#endif
|
|
|
|
//
|
|
// Save, skip filename arg
|
|
//
|
|
FileName = Argv[0];
|
|
Argc--;
|
|
Argv++;
|
|
|
|
//
|
|
// Get the same path with the application itself
|
|
//
|
|
if (strlen (FileName) > _MAX_PATH - 1) {
|
|
Error ("FMMT", 0, 2000, "Parameter: The input filename is too long", NULL);
|
|
return 1;
|
|
}
|
|
strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1);
|
|
FullGuidToolDefinition[_MAX_PATH - 1] = 0;
|
|
FileNameIndex = strlen (FullGuidToolDefinition);
|
|
while (FileNameIndex != 0) {
|
|
FileNameIndex --;
|
|
if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
|
|
FullGuidToolDefinition[FileNameIndex] = 0;
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// Build the path list for Config file scan. The priority is below.
|
|
// 1. Scan the current path
|
|
// 2. Scan the same path with the application itself
|
|
// 3. Scan the current %PATH% of OS environment
|
|
// 4. Use the build-in default configuration
|
|
//
|
|
PathList = getenv("PATH");
|
|
if (PathList == NULL) {
|
|
Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
|
|
return 1;
|
|
}
|
|
EnvLen = strlen(PathList);
|
|
NewPathList = (char *)calloc(
|
|
strlen (".")
|
|
+ strlen (";")
|
|
+ strlen (FullGuidToolDefinition)
|
|
+ strlen (";")
|
|
+ EnvLen
|
|
+ 1,
|
|
sizeof(char)
|
|
);
|
|
if (NewPathList == NULL) {
|
|
Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
PathList = NULL;
|
|
free (PathList);
|
|
return 1;
|
|
}
|
|
#ifndef __GNUC__
|
|
sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList);
|
|
#else
|
|
sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList);
|
|
#endif
|
|
PathList = NULL;
|
|
free (PathList);
|
|
|
|
//
|
|
// Load Guid Tools definition
|
|
//
|
|
InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
|
|
free (NewPathList);
|
|
if (InFilePath != NULL) {
|
|
printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath);
|
|
mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
|
|
free (InFilePath);
|
|
} else {
|
|
//
|
|
// Use the pre-defined standard guided tools.
|
|
//
|
|
printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n");
|
|
mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
|
|
}
|
|
|
|
if ((strcmp(Argv[0], "-v") == 0) || (strcmp(Argv[0], "-V") == 0)) {
|
|
//
|
|
// View the FD binary image information.
|
|
//
|
|
if (Argc <= 1) {
|
|
Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
|
|
Usage ();
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Open the file containing the FV to check whether it exist or not
|
|
//
|
|
CheckFileExist = fopen (Argv[1], "rb");
|
|
if (CheckFileExist == NULL) {
|
|
Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
|
|
return 1;
|
|
}
|
|
fclose(CheckFileExist);
|
|
|
|
Status = FmmtImageView(Argv[1], NULL, TRUE, NULL);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
Error("FMMT", 0, 1001, "Error while view the FD image file.", "");
|
|
LibRmDir (TemDir);
|
|
return 1;
|
|
}
|
|
|
|
} else if ((strcmp(Argv[0], "-d") == 0) || (strcmp(Argv[0], "-D") == 0)) {
|
|
//
|
|
// Delete some named FFS file from FD binary image.
|
|
//
|
|
if (!((Argc == 4) || ((Argc - 3) % 2 == 0))) {
|
|
Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
|
|
Usage ();
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Open the file containing the FV to check whether it exist or not
|
|
//
|
|
CheckFileExist = fopen (Argv[1], "rb");
|
|
if (CheckFileExist == NULL) {
|
|
Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
|
|
return 1;
|
|
}
|
|
fclose(CheckFileExist);
|
|
|
|
if ((Argc - 3) % 2 == 0) {
|
|
FileData = malloc(sizeof (Data) * (Argc - 3)/2);
|
|
if (FileData == NULL) {
|
|
Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
return 1;
|
|
}
|
|
for(index = 0; index < (Argc - 3)/2; index ++) {
|
|
p = malloc(sizeof (FILENode));
|
|
if (p == NULL) {
|
|
Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
free (FileData);
|
|
return 1;
|
|
}
|
|
p -> FileName = Argv[3 + index * 2];
|
|
p -> SubLevel = 0;
|
|
exist = -1;
|
|
for (j = 0; j < count; j ++) {
|
|
if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
|
|
exist = j;
|
|
break;
|
|
}
|
|
}
|
|
if (exist >= 0) {
|
|
p -> Next = (FileData + j) -> OldFile;
|
|
(FileData + j) -> OldFile = p;
|
|
} else {
|
|
(FileData + count) -> NewFile = NULL;
|
|
(FileData + count) -> FdData = NULL;
|
|
(FileData + count) -> FvLevel = 0;
|
|
(FileData + count) -> FvInFd = NULL;
|
|
(FileData + count) -> FvId = Argv[2 + index * 2];;
|
|
(FileData + count) -> OldFile = p;
|
|
p -> Next = NULL;
|
|
count ++;
|
|
}
|
|
}
|
|
|
|
if (count <= 0) {
|
|
Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
|
|
}
|
|
for (index = 0; index < count; index ++) {
|
|
for (j = index + 1; j < count; j ++) {
|
|
if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
|
|
CHAR8 *tmp = (FileData + index)->FvId;
|
|
FILENode *t = (FileData + index)->OldFile;
|
|
(FileData + index)->FvId = (FileData + j)->FvId;
|
|
(FileData + index)-> OldFile = (FileData + j)->OldFile;
|
|
(FileData + j)-> OldFile = t;
|
|
(FileData + j)-> FvId = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete some FFS file
|
|
//
|
|
Status = FmmtImageDelete(Argv[1], FileData, count, Argv[Argc-1]);
|
|
for (index = 0; index < count; index ++) {
|
|
if ((FileData + index) ->NewFile != NULL) {
|
|
free ((FileData + index)->NewFile);
|
|
(FileData + index)->NewFile = NULL;
|
|
}
|
|
if ((FileData + index)->OldFile != NULL) {
|
|
free ((FileData + index)->OldFile);
|
|
(FileData + index)->OldFile = NULL;
|
|
}
|
|
}
|
|
for (index = 0; index < count; index ++) {
|
|
if ((FileData + index)->FdData != NULL) {
|
|
LibFmmtFreeFd ((FileData + index)->FdData);
|
|
}
|
|
}
|
|
free (FileData);
|
|
if (EFI_ERROR (Status)) {
|
|
Error("FMMT", 0, 1001, "Error while delete some named ffs file from the FD image file.", "");
|
|
LibRmDir (TemDir);
|
|
return 1;
|
|
}
|
|
} else {
|
|
//
|
|
// Delete FV
|
|
//
|
|
Status = FmmtImageDeleteFv(Argv[1], Argv[2], Argv[3]);
|
|
if (EFI_ERROR (Status)) {
|
|
Error("FMMT", 0, 1001, "Error while delete the entire FV from the FD image file.", "");
|
|
LibRmDir (TemDir);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
} else if ((strcmp(Argv[0], "-a") == 0) || (strcmp(Argv[0], "-A") == 0)) {
|
|
//
|
|
// Add some named FFS file into FD binary image.
|
|
//
|
|
if ((Argc - 3 ) % 2 != 0) {
|
|
Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
|
|
Usage ();
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Open the file containing the FV to check whether it exist or not
|
|
//
|
|
CheckFileExist = fopen (Argv[1], "rb");
|
|
if (CheckFileExist == NULL) {
|
|
Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
|
|
return 1;
|
|
}
|
|
fclose(CheckFileExist);
|
|
|
|
//
|
|
// Check whether the new added file exist or not.
|
|
//
|
|
for (index = 1; index < (Argc - 1) / 2; index ++) {
|
|
CheckFileExist = fopen(Argv[2 * index + 1], "rb");
|
|
if (CheckFileExist == NULL) {
|
|
Error("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[2 * index + 1]);
|
|
return 1;
|
|
}
|
|
fclose(CheckFileExist);
|
|
}
|
|
|
|
FileData = malloc(sizeof (Data) * (Argc - 3)/2);
|
|
if (FileData == NULL) {
|
|
Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
return 1;
|
|
}
|
|
for(index = 0; index < (Argc - 3)/2; index ++) {
|
|
p = malloc(sizeof (FILENode));
|
|
if (p == NULL) {
|
|
Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
free (FileData);
|
|
return 1;
|
|
}
|
|
p -> FileName = Argv[3 + index * 2];
|
|
p -> SubLevel = 0;
|
|
exist = -1;
|
|
for (j = 0; j < count; j ++) {
|
|
if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) {
|
|
exist = j;
|
|
break;
|
|
}
|
|
}
|
|
if (exist >= 0) {
|
|
p -> Next = (FileData + j) -> NewFile;
|
|
(FileData + j) -> NewFile = p;
|
|
} else {
|
|
(FileData + count) -> OldFile = NULL;
|
|
(FileData + count) -> FdData = NULL;
|
|
(FileData + count) -> FvLevel = 0;
|
|
(FileData + count) -> FvInFd = NULL;
|
|
(FileData + count) -> FvId = Argv[2 + index * 2];
|
|
(FileData + count) -> NewFile = p;
|
|
p -> Next = NULL;
|
|
count ++;
|
|
}
|
|
}
|
|
|
|
if (count <= 0) {
|
|
Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
|
|
}
|
|
|
|
for (index = 0; index < count; index ++) {
|
|
for (j = index + 1; j < count; j ++) {
|
|
if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
|
|
CHAR8 *tmp = (FileData + index)->FvId;
|
|
FILENode *temp = (FileData + index)->NewFile;
|
|
(FileData + index)->FvId = (FileData + j)->FvId;
|
|
(FileData + index)-> NewFile = (FileData + j)->NewFile;
|
|
(FileData + j)-> NewFile = temp;
|
|
(FileData + j)-> FvId = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = FmmtImageAdd(Argv[1], FileData, count, Argv[Argc-1]);
|
|
for (index = 0; index < count; index ++) {
|
|
if ((FileData + index)->NewFile != NULL) {
|
|
free ((FileData + index)->NewFile);
|
|
(FileData + index)->NewFile = NULL;
|
|
}
|
|
if ((FileData + index)->OldFile != NULL) {
|
|
free ((FileData + index)->OldFile);
|
|
(FileData + index)->OldFile = NULL;
|
|
}
|
|
}
|
|
for (index = 0; index < count; index ++) {
|
|
if ((FileData + index)->FdData != NULL) {
|
|
LibFmmtFreeFd ((FileData + index)->FdData);
|
|
}
|
|
}
|
|
free (FileData);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
Error("FMMT", 0, 1001, "Error while add some named ffs file into the FD image file.", "");
|
|
LibRmDir (TemDir);
|
|
return 1;
|
|
}
|
|
|
|
} else if ((strcmp(Argv[0], "-r") == 0) || (strcmp(Argv[0], "-R") == 0)) {
|
|
//
|
|
// Replace some named FFS file in the FD binary.
|
|
//
|
|
if ((Argc - 3) % 3 != 0) {
|
|
Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", "");
|
|
Usage();
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Open the file containing the FV to check whether it exist or not
|
|
//
|
|
CheckFileExist = fopen (Argv[1], "rb");
|
|
if (CheckFileExist == NULL) {
|
|
Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the <input-binary-file> exist!", Argv[1]);
|
|
return 1;
|
|
}
|
|
fclose(CheckFileExist);
|
|
|
|
//
|
|
// Check whether the new FFS file exist or not.
|
|
//
|
|
for (index = 1; index < Argc/3; index ++) {
|
|
CheckFileExist = fopen(Argv[3 * index + 1], "rb");
|
|
if (CheckFileExist == NULL) {
|
|
Error ("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[3 * index + 1]);
|
|
return 1;
|
|
}
|
|
fclose(CheckFileExist);
|
|
}
|
|
|
|
FileData = malloc(sizeof (Data) * (Argc - 3)/3);
|
|
if (FileData == NULL) {
|
|
Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
return 1;
|
|
}
|
|
for(index = 0; index < (Argc - 3)/3; index ++) {
|
|
p = malloc(sizeof (FILENode)); //p for old file
|
|
if (p == NULL) {
|
|
Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
free (FileData);
|
|
return 1;
|
|
}
|
|
q = malloc(sizeof (FILENode)); //q for new file
|
|
if (q == NULL) {
|
|
Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL);
|
|
free (FileData);
|
|
free (p);
|
|
return 1;
|
|
}
|
|
p -> FileName = Argv[3 + index * 3];
|
|
q -> FileName = Argv[4 + index * 3];
|
|
p -> SubLevel = 0;
|
|
q -> SubLevel = 0;
|
|
exist = -1;
|
|
for (j = 0; j < count; j ++) {
|
|
if ((strcmp(Argv[2 + index * 3], (FileData + j) -> FvId) == 0)) {
|
|
exist = j;
|
|
break;
|
|
}
|
|
}
|
|
if (exist >= 0) {
|
|
p -> Next = (FileData + j) -> OldFile;
|
|
(FileData + j) -> OldFile = p;
|
|
q -> Next = (FileData + j) -> NewFile;
|
|
(FileData + j) -> NewFile = q;
|
|
} else {
|
|
(FileData + count) -> FdData = NULL;
|
|
(FileData + count) -> FvLevel = 0;
|
|
(FileData + count) -> FvInFd = NULL;
|
|
(FileData + count) -> FvId = Argv[2 + index * 3];;
|
|
(FileData + count) -> OldFile = p;
|
|
(FileData + count) -> NewFile = q;
|
|
p -> Next = NULL;
|
|
q -> Next = NULL;
|
|
count ++;
|
|
}
|
|
}
|
|
|
|
if (count <= 0) {
|
|
Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!");
|
|
}
|
|
for (index = 0; index < count; index ++) {
|
|
for (j = index + 1; j < count; j ++) {
|
|
if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) {
|
|
CHAR8 *tmp = (FileData + index)->FvId;
|
|
FILENode *Old = (FileData + index)->OldFile;
|
|
FILENode *New = (FileData + index)->NewFile;
|
|
(FileData + index)->FvId = (FileData + j)->FvId;
|
|
(FileData + index)->OldFile = (FileData + j)->OldFile;
|
|
(FileData + index)->NewFile = (FileData + j)->NewFile;
|
|
(FileData + j)->OldFile = Old;
|
|
(FileData + j)->NewFile = New;
|
|
(FileData + j)->FvId = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = FmmtImageReplace(Argv[1], FileData, count, Argv[Argc-1]);
|
|
for (index = 0; index < count; index ++) {
|
|
if ((FileData + index)->NewFile != NULL) {
|
|
free ((FileData + index)->NewFile);
|
|
(FileData + index)->NewFile = NULL;
|
|
}
|
|
if ((FileData + index)->OldFile != NULL) {
|
|
free ((FileData + index)->OldFile);
|
|
(FileData + index)->OldFile = NULL;
|
|
}
|
|
}
|
|
for (index = 0; index < count; index ++) {
|
|
if ((FileData + index)->FdData != NULL) {
|
|
LibFmmtFreeFd ((FileData + index)->FdData);
|
|
}
|
|
}
|
|
free (FileData);
|
|
if (EFI_ERROR (Status)) {
|
|
Error("FMMT", 0, 1001, "Error while replace the named ffs file in the FD image file with the new ffs file.", "");
|
|
LibRmDir (TemDir);
|
|
return 1;
|
|
}
|
|
|
|
} else if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
|
|
(strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
|
|
//
|
|
// print help information to user.
|
|
//
|
|
Usage();
|
|
|
|
} else {
|
|
//
|
|
// Invalid parameter.
|
|
//
|
|
printf("\n");
|
|
Error("FMMT", 0, 1001, "Invalid parameter", Argv[0]);
|
|
Usage();
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|