/**@file
This utility is part of build process for IA32/X64 FD.
It generates FIT table.
Copyright (c) 2010-2021, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "FitGen.h"
//
// FIT spec
//
#pragma pack (1)
typedef struct {
UINT64 Address;
UINT8 Size[3];
UINT8 Rsvd;
UINT16 Version;
UINT8 Type:7;
UINT8 C_V:1;
UINT8 Checksum;
} FIRMWARE_INTERFACE_TABLE_ENTRY;
//
// Struct for policy
//
typedef struct {
UINT16 IndexPort;
UINT16 DataPort;
UINT8 Width;
UINT8 Bit;
UINT16 Index;
UINT8 Size[3];
UINT8 Rsvd;
UINT16 Version; // == 0
UINT8 Type:7;
UINT8 C_V:1;
UINT8 Checksum;
} FIRMWARE_INTERFACE_TABLE_ENTRY_PORT;
#define FIT_ALIGNMENT 0x3F // 0xF is required previously, but if we need exclude FIT, we must set 64 bytes alignment.
#define BIOS_MODULE_ALIGNMENT 0x3F // 64 bytes for AnC
#define MICROCODE_ALIGNMENT 0x7FF
#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE 256
#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE 384
#define ACM_HEADER_VERSION_3 (3 << 16)
#define ACM_HEADER_VERSION_0 (0)
#define ACM_MODULE_TYPE_CHIPSET_ACM 2
#define ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET 0x1
#define ACM_MODULE_SUBTYPE_ANC_MODULE 0x2
#define ACM_MODULE_FLAG_PREPRODUCTION 0x4000
#define ACM_MODULE_FLAG_DEBUG_SIGN 0x8000
typedef struct {
UINT16 ModuleType;
UINT16 ModuleSubType;
UINT32 HeaderLen;
UINT32 HeaderVersion;
UINT16 ChipsetID;
UINT16 Flags;
UINT32 ModuleVendor;
UINT32 Date;
UINT32 Size;
UINT16 TxtSvn;
UINT16 SeSvn;
UINT32 CodeControl;
UINT32 ErrorEntryPoint;
UINT32 GDTLimit;
UINT32 GDTBasePtr;
UINT32 SegSel;
UINT32 EntryPoint;
UINT8 Rsvd2[64];
UINT32 KeySize; // 64
UINT32 ScratchSize; // 2 * KeySize + 15
//UINT8 RSAPubKey[64 * 4]; // KeySize * 4
//UINT32 RSAPubExp;
//UINT8 RSASig[256];
// End of AC module header
//UINT8 Scratch[(64 * 2 + 15) * 4]; // ScratchSize * 4
// User Area
//UINT8 UserArea[1];
} ACM_FORMAT;
#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_3 0x03
#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_4 0x04
#define CHIPSET_ACM_INFORMATION_TABLE_VERSION CHIPSET_ACM_INFORMATION_TABLE_VERSION_3
#define CHIPSET_ACM_INFORMATION_TABLE_GUID_V03 \
{ 0x7FC03AAA, 0x18DB46A7, 0x8F69AC2E, 0x5A7F418D }
#define CHIPSET_ACM_TYPE_BIOS 0
#define CHIPSET_ACM_TYPE_SINIT 1
typedef struct {
UINT32 Guid0;
UINT32 Guid1;
UINT32 Guid2;
UINT32 Guid3;
} ACM_GUID;
typedef struct {
ACM_GUID Guid;
UINT8 ChipsetACMType;
UINT8 Version;
UINT16 Length;
UINT32 ChipsetIDList;
UINT32 OsSinitTableVer;
UINT32 MinMleHeaderVer;
//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3)
UINT32 Capabilities;
UINT8 AcmVersion;
UINT8 AcmRevision[3];
//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4)
UINT32 ProcessorIDList;
//#endif
//#endif
} CHIPSET_ACM_INFORMATION_TABLE;
#define ACM_CHIPSET_ID_REVISION_ID_MAKE 0x1
typedef struct {
UINT32 Flags;
UINT16 VendorID;
UINT16 DeviceID;
UINT16 RevisionID;
UINT8 Reserved[6];
} ACM_CHIPSET_ID;
typedef struct {
UINT32 Count;
ACM_CHIPSET_ID ChipsetID[1];
} CHIPSET_ID_LIST;
typedef struct {
UINT32 FMS;
UINT32 FMSMask;
UINT64 PlatformID;
UINT64 PlatformMask;
} ACM_PROCESSOR_ID;
typedef struct {
UINT32 Count;
ACM_PROCESSOR_ID ProcessorID[1];
} PROCESSOR_ID_LIST;
#pragma pack ()
ACM_GUID mChipsetAcmInformationTableGuid03 = CHIPSET_ACM_INFORMATION_TABLE_GUID_V03;
//
// BIOS INFO data structure
// This is self contained data structure for BIOS info
//
#pragma pack (1)
#define BIOS_INFO_SIGNATURE SIGNATURE_64 ('$', 'B', 'I', 'O', 'S', 'I', 'F', '$')
typedef struct {
UINT64 Signature;
UINT32 EntryCount;
UINT32 Reserved;
//BIOS_INFO_STRUCT Struct[EntryCount];
} BIOS_INFO_HEADER;
//
// BIOS_INFO_STRUCT attributes
// bits[0:3] means general attributes
// bits[4:7] means type specific attributes
//
#define BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT 0x01
#define BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION 0x10
#define BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB 0x10
typedef struct {
//
// FitTable entry type
//
UINT8 Type;
//
// BIOS_INFO_STRUCT attributes
//
UINT8 Attributes;
//
// FitTable entry version
//
UINT16 Version;
//
// FitTable entry real size
//
UINT32 Size;
//
// FitTable entry address
//
UINT64 Address;
} BIOS_INFO_STRUCT;
#pragma pack ()
#define MAX_BIOS_MODULE_ENTRY 0x20
#define MAX_MICROCODE_ENTRY 0x20
#define MAX_OPTIONAL_ENTRY 0x20
#define MAX_PORT_ENTRY 0x20
#define DEFAULT_FIT_TABLE_POINTER_OFFSET 0x40
#define DEFAULT_FIT_ENTRY_VERSION 0x0100
#define TOP_FLASH_ADDRESS (gFitTableContext.TopFlashAddressRemapValue)
#define MEMORY_TO_FLASH(FileBuffer, FvBuffer, FvSize) \
(UINTN)(TOP_FLASH_ADDRESS - ((UINTN)(FvBuffer) + (UINTN)(FvSize) - (UINTN)(FileBuffer)))
#define FLASH_TO_MEMORY(Address, FvBuffer, FvSize) \
(VOID *)(UINTN)((UINTN)(FvBuffer) + (UINTN)(FvSize) - (TOP_FLASH_ADDRESS - (UINTN)(Address)))
#define FIT_TABLE_TYPE_HEADER 0
#define FIT_TABLE_TYPE_MICROCODE 1
#define FIT_TABLE_TYPE_STARTUP_ACM 2
#define FIT_TABLE_TYPE_DIAGNST_ACM 3
#define FIT_TABLE_TYPE_BIOS_MODULE 7
#define FIT_TABLE_TYPE_TPM_POLICY 8
#define FIT_TABLE_TYPE_BIOS_POLICY 9
#define FIT_TABLE_TYPE_TXT_POLICY 10
#define FIT_TABLE_TYPE_KEY_MANIFEST 11
#define FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST 12
#define FIT_TABLE_TYPE_BIOS_DATA_AREA 13
#define FIT_TABLE_TYPE_CSE_SECURE_BOOT 16
#define FIT_TABLE_SUBTYPE_FIT_PATCH_MANIFEST 12
#define FIT_TABLE_SUBTYPE_ACM_MANIFEST 13
//
// With OptionalModule Address isn't known until free space has been
// identified and the optional module has been copied into the FLASH
// image buffer (or initialized to be populated later by another program).
// This is very dangerous code as it can truncate 64b pointers to
// allocated memory buffers. The full pointer is in Buffer for that case.
//
typedef struct {
UINT32 Type;
UINT32 SubType; // Used by OptionalModule only
UINT32 Address;
UINT8 *Buffer; // Used by OptionalModule only
UINT32 Size;
UINT32 Version; // Used by OptionalModule and PortModule only
} FIT_TABLE_CONTEXT_ENTRY;
typedef struct {
BOOLEAN Clear;
UINT32 FitTablePointerOffset;
UINT32 FitTablePointerOffset2;
UINT32 FitEntryNumber;
UINT32 BiosModuleNumber;
UINT32 MicrocodeNumber;
UINT32 OptionalModuleNumber;
UINT32 PortModuleNumber;
UINT32 GlobalVersion;
UINT32 FitHeaderVersion;
FIT_TABLE_CONTEXT_ENTRY StartupAcm;
UINT32 StartupAcmVersion;
FIT_TABLE_CONTEXT_ENTRY DiagnstAcm;
UINT32 DiagnstAcmVersion;
FIT_TABLE_CONTEXT_ENTRY BiosModule[MAX_BIOS_MODULE_ENTRY];
UINT32 BiosModuleVersion;
FIT_TABLE_CONTEXT_ENTRY Microcode[MAX_MICROCODE_ENTRY];
BOOLEAN MicrocodeIsAligned;
UINT32 MicrocodeAlignValue;
UINT32 MicrocodeVersion;
FIT_TABLE_CONTEXT_ENTRY OptionalModule[MAX_OPTIONAL_ENTRY];
FIT_TABLE_CONTEXT_ENTRY PortModule[MAX_PORT_ENTRY];
UINT64 TopFlashAddressRemapValue;
} FIT_TABLE_CONTEXT;
FIT_TABLE_CONTEXT gFitTableContext = {0};
unsigned int
xtoi (
char *str
);
VOID
PrintUtilityInfo (
VOID
)
/*++
Routine Description:
Displays the standard utility information to STDOUT
Arguments:
None
Returns:
None
--*/
{
printf (
"%s - Tiano IA32/X64 FIT table generation Utility for FIT spec revision 1.2."" Version %i.%i\n\n",
UTILITY_NAME,
UTILITY_MAJOR_VERSION,
UTILITY_MINOR_VERSION
);
}
VOID
PrintUsage (
VOID
)
/*++
Routine Description:
Displays the utility usage syntax to STDOUT
Arguments:
None
Returns:
None
--*/
{
printf ("Usage (generate): %s [-D] InputFvRecoveryFile OutputFvRecoveryFile\n"
"\t[-V ]\n"
"\t[-F ] [-F ] [-V ]\n"
"\t[-NA]\n"
"\t[-A ]\n"
"\t[-REMAP \n"
"\t[-CLEAR]\n"
"\t[-L ]\n"
"\t[-LF ]\n"
"\t[-I ]\n"
"\t[-S |] [-V ]\n"
"\t[-U |]\n"
"\t[-B ] [-B ...] [-V ]\n"
"\t[-M ] [-M ...]|[-U ||] [-V ]\n"
"\t[-O RecordType |||| [-V ]] [-O ... [-V ...]]\n"
"\t[-P RecordType [-V ]] [-P ... [-V ...]]\n"
, UTILITY_NAME);
printf (" Where:\n");
printf ("\t-D - It is FD file instead of FV file. (The tool will search FV file)\n");
printf ("\tInputFvRecoveryFile - Name of the input FvRecovery.fv file.\n");
printf ("\tOutputFvRecoveryFile - Name of the output FvRecovery.fv file.\n");
printf ("\tFitTablePointerOffset - FIT table pointer offset. 0x%x as default. 0x18 for current soon to be obsoleted CPUs. User can set both.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
printf ("\tBiosInfoGuid - Guid of BiosInfo Module. If this module exists, StartupAcm/Bios/Microcode can be optional.\n");
printf ("\tStartupAcmAddress - Address of StartupAcm.\n");
printf ("\tStartupAcmSize - Size of StartupAcm.\n");
printf ("\tStartupAcmGuid - Guid of StartupAcm Module, if StartupAcm is in a BiosModule, it will be excluded form that.\n");
printf ("\tDiagnstAcmAddress - Address of DiagnstAcm.\n");
printf ("\tDiagnstAcmGuid - Guid of DiagnstAcm Module, if DiagnstAcm is in a BiosModule, it will be excluded from that.\n");
printf ("\tBiosModuleAddress - Address of BiosModule. User should ensure there is no overlap.\n");
printf ("\tBiosModuleSize - Size of BiosModule.\n");
printf ("\tMicrocodeAddress - Address of Microcode.\n");
printf ("\tMicrocodeSize - Size of Microcode.\n");
printf ("\tMicrocodeFv - Name of Microcode.fv file.\n");
printf ("\tMicrocodeBase - The base address of Microcode.fv in final FD image.\n");
printf ("\tMicrocodeRegionOffset - Offset of Microcode region in input FD image.\n");
printf ("\tMicrocodeRegionSize - Size of Microcode region in input FD image.\n");
printf ("\tMicrocodeGuid - Guid of Microcode Module.\n");
printf ("\tMicrocodeSlotSize - Occupied region size of each Microcode binary.\n");
printf ("\tMicrocodeFfsGuid - Guid of FFS which is used to save Microcode binary");
printf ("\t-LF - Microcode Slot mode without FFS check, treat all Microcode FV as slot mode. In this case the Microcode FV should only contain one FFS.\n");
printf ("\t-NA - No 0x800 aligned Microcode requirement. No -NA means Microcode is aligned with option MicrocodeAlignment value.\n");
printf ("\tMicrocodeAlignment - HEX value of Microcode alignment. Ignored if \"-NA\" is specified. Default value is 0x800. The Microcode update data must start at a 16-byte aligned linear address.\n");
printf ("\tRecordType - FIT entry record type. User should ensure it is ordered.\n");
printf ("\tRecordDataAddress - FIT entry record data address.\n");
printf ("\tRecordDataSize - FIT entry record data size.\n");
printf ("\tRecordDataGuid - FIT entry record data GUID.\n");
printf ("\tRecordBinFile - FIT entry record data binary file.\n");
printf ("\tCseRecordSubType - FIT entry record subtype. Use to further distinguish CSE entries (see FIT spec revision 1.2 chapter 4.12).\n");
printf ("\tFitEntryDefaultVersion - The default version for all FIT table entries. 0x%04x is used if this is not specified.\n", DEFAULT_FIT_ENTRY_VERSION);
printf ("\tFitHeaderVersion - The version for FIT header. (Override default version)\n");
printf ("\tStartupAcmVersion - The version for StartupAcm. (Override default version)\n");
printf ("\tBiosModuleVersion - The version for BiosModule. (Override default version)\n");
printf ("\tMicrocodeVersion - The version for Microcode. (Override default version)\n");
printf ("\tRecordVersion - The version for Record. (Override default version)\n");
printf ("\tIndexPort - The Index Port Number.\n");
printf ("\tDataPort - The Data Port Number.\n");
printf ("\tWidth - The Width of the port.\n");
printf ("\tBit - The Bit Number of the port.\n");
printf ("\tIndex - The Index Number of the port.\n");
printf ("\nUsage (view): %s [-view] InputFile -F \n", UTILITY_NAME);
printf (" Where:\n");
printf ("\tInputFile - Name of the input file.\n");
printf ("\tFitTablePointerOffset - FIT table pointer offset from end of file. 0x%x as default.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
printf ("\nTool return values:\n");
printf ("\tSTATUS_SUCCESS=%d, STATUS_WARNING=%d, STATUS_ERROR=%d\n", STATUS_SUCCESS, STATUS_WARNING, STATUS_ERROR);
}
VOID *
SetMem (
OUT VOID *Buffer,
IN UINTN Length,
IN UINT8 Value
)
{
//
// Declare the local variables that actually move the data elements as
// volatile to prevent the optimizer from replacing this function with
// the intrinsic memset()
//
volatile UINT8 *Pointer;
Pointer = (UINT8*)Buffer;
while (Length-- > 0) {
*(Pointer++) = Value;
}
return Buffer;
}
BOOLEAN
CheckPath (
IN CHAR8 * String
)
{
//
//Return FLASE if input file path include % character or is NULL
//
CHAR8 *StrPtr;
StrPtr = String;
if (StrPtr == NULL) {
return FALSE;
}
if (*StrPtr == 0) {
return FALSE;
}
while (*StrPtr != '\0') {
if (*StrPtr == '%') {
return FALSE;
}
StrPtr++;
}
return TRUE;
}
STATUS
ReadInputFile (
IN CHAR8 *FileName,
OUT UINT8 **FileData,
OUT UINT32 *FileSize,
OUT UINT8 **FileBufferRaw OPTIONAL
)
/*++
Routine Description:
Read input file
Arguments:
FileName - The input file name
FileData - The input file data, the memory is aligned.
FileSize - The input file size
FileBufferRaw - The memory to hold input file data. The caller must free the memory.
Returns:
STATUS_SUCCESS - The file found and data read
STATUS_ERROR - The file data is not read
STATUS_WARNING - The file is not found
--*/
{
FILE *FpIn;
UINT32 TempResult;
//
//Check the File Path
//
if (!CheckPath(FileName)) {
Error (NULL, 0, 0, "File path is invalid!", NULL);
return STATUS_ERROR;
}
//
// Open the Input FvRecovery.fv file
//
if ((FpIn = fopen (FileName, "rb")) == NULL) {
//
// Return WARNING, let caller make decision
//
// Error (NULL, 0, 0, "Unable to open file", FileName);
return STATUS_WARNING;
}
//
// Get the Input FvRecovery.fv file size
//
fseek (FpIn, 0, SEEK_END);
*FileSize = ftell (FpIn);
//
// Read the contents of input file to memory buffer
//
if (FileBufferRaw != NULL) {
*FileBufferRaw = (UINT8 *) malloc (*FileSize + 0x10000);
if (NULL == *FileBufferRaw) {
Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
fclose (FpIn);
return STATUS_ERROR;
}
TempResult = 0x10000 - (UINT32) ((UINTN)*FileBufferRaw & 0x0FFFF);
*FileData = (UINT8 *)((UINTN)*FileBufferRaw + TempResult);
} else {
*FileData = (UINT8 *) malloc (*FileSize);
if (NULL == *FileData) {
Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
fclose (FpIn);
return STATUS_ERROR;
}
}
fseek (FpIn, 0, SEEK_SET);
TempResult = fread (*FileData, 1, *FileSize, FpIn);
if (TempResult != *FileSize) {
Error (NULL, 0, 0, "Read input file error!", NULL);
if (FileBufferRaw != NULL) {
free ((VOID *)*FileBufferRaw);
} else {
free ((VOID *)*FileData);
}
fclose (FpIn);
return STATUS_ERROR;
}
//
// Close the input FvRecovery.fv file
//
fclose (FpIn);
return STATUS_SUCCESS;
}
UINT8 *
FindNextFvHeader (
IN UINT8 *FileBuffer,
IN UINTN FileLength
)
/*++
Routine Description:
Find next FvHeader in the FileBuffer
Parameters:
FileBuffer - The start FileBuffer which needs to be searched
FileLength - The whole File Length.
Return:
FvHeader - The FvHeader is found successfully.
NULL - The FvHeader is not found.
--*/
{
UINT8 *FileHeader;
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
UINT16 FileChecksum;
FileHeader = FileBuffer;
for (; (UINTN)FileBuffer < (UINTN)FileHeader + FileLength; FileBuffer += 8) {
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer;
if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
//
// potential candidate
//
//
// Check checksum
//
if (FvHeader->FvLength > FileLength) {
continue;
}
if (FvHeader->HeaderLength >= FileLength) {
continue;
}
FileChecksum = CalculateChecksum16 ((UINT16 *)FileBuffer, FvHeader->HeaderLength / sizeof (UINT16));
if (FileChecksum != 0) {
continue;
}
//
// Check revision and reserved field
//
#if (PI_SPECIFICATION_VERSION < 0x00010000)
if ((FvHeader->Revision == EFI_FVH_REVISION) &&
(FvHeader->Reserved[0] == 0) &&
(FvHeader->Reserved[1] == 0) &&
(FvHeader->Reserved[2] == 0) ){
return FileBuffer;
}
#else
if ((FvHeader->Revision == EFI_FVH_PI_REVISION) &&
(FvHeader->Reserved[0] == 0) ){
return FileBuffer;
}
#endif
}
}
return NULL;
}
UINT8 *
FindFileFromFvByGuid (
IN UINT8 *FvBuffer,
IN UINT32 FvSize,
IN EFI_GUID *Guid,
OUT UINT32 *FileSize
)
/*++
Routine Description:
Find File with GUID in an FV
Arguments:
FvBuffer - FV binary buffer
FvSize - FV size
Guid - File GUID value to be searched
FileSize - Guid File size
Returns:
FileLocation - Guid File location.
NULL - Guid File is not found.
--*/
{
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
EFI_FFS_FILE_HEADER *FileHeader;
UINT64 FvLength;
EFI_GUID *TempGuid;
UINT8 *FixPoint;
UINTN Offset;
UINTN FileLength;
UINTN FileOccupiedSize;
//
// Find the FFS file
//
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader (FvBuffer, FvSize);
if (NULL == FvHeader) {
return NULL;
}
while (TRUE) {
FvLength = FvHeader->FvLength;
//
// Prepare to walk the FV image
//
InitializeFvLib (FvHeader, (UINT32)FvLength);
FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
Offset = (UINTN) FileHeader - (UINTN) FvHeader;
while (Offset < FvLength) {
TempGuid = (EFI_GUID *)&(FileHeader->Name);
FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
if ((CompareGuid (TempGuid, Guid)) == 0) {
//
// Good! Find it.
//
FixPoint = ((UINT8 *)FileHeader + sizeof(EFI_FFS_FILE_HEADER));
//
// Find the position of file module, the offset
// between the position and the end of FvRecovery.fv file
// should not exceed 128kB to prevent reset vector from
// outside legacy E and F segment
//
if ((UINTN)FvHeader + FvLength - (UINTN)FixPoint > 0x20000) {
// printf ("WARNING: The position of file module is not in E and F segment!\n");
// return NULL;
}
*FileSize = FileLength - sizeof(EFI_FFS_FILE_HEADER);
#if (PI_SPECIFICATION_VERSION < 0x00010000)
if (FileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
*FileSize -= sizeof(EFI_FFS_FILE_TAIL);
}
#endif
return FixPoint;
}
FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize);
Offset = (UINTN) FileHeader - (UINTN) FvHeader;
}
//
// Not found, check next FV
//
if ((UINTN)FvBuffer + FvSize > (UINTN)FvHeader + FvLength) {
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader ((UINT8 *)FvHeader + (UINTN)FvLength, (UINTN)FvBuffer + FvSize - ((UINTN)FvHeader + (UINTN)FvLength));
if (FvHeader == NULL) {
break;
}
} else {
break;
}
}
//
// Not found
//
return NULL;
}
BOOLEAN
IsGuidData (
IN CHAR8 *StringData,
OUT EFI_GUID *Guid
)
/*++
Routine Description:
Check whether a string is a GUID
Arguments:
StringData - the String
Guid - Guid to hold the value
Returns:
TRUE - StringData is a GUID, and Guid field is filled.
FALSE - StringData is not a GUID
--*/
{
if (strlen (StringData) != strlen ("00000000-0000-0000-0000-000000000000")) {
return FALSE;
}
if ((StringData[8] != '-') ||
(StringData[13] != '-') ||
(StringData[18] != '-') ||
(StringData[23] != '-') ) {
return FALSE;
}
StringToGuid (StringData, Guid);
return TRUE;
}
VOID
CheckOverlap (
IN UINT32 Address,
IN UINT32 Size
)
{
INTN Index;
for (Index = 0; Index < (INTN)gFitTableContext.BiosModuleNumber; Index ++) {
if ((gFitTableContext.BiosModule[Index].Address <= Address) &&
((gFitTableContext.BiosModule[Index].Size - Size) >= (Address - gFitTableContext.BiosModule[Index].Address))) {
UINT32 TempSize;
INT32 SubIndex;
//
// Found overlap, split BiosModuleEntry
// Currently only support StartupAcm in 1 BiosModule. It does not support StartupAcm across 2 BiosModule or more.
//
if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
Error (NULL, 0, 0, "Too many Bios Module!", NULL);
return ;
}
if (Address != gFitTableContext.BiosModule[Index].Address) {
//
// Skip the entry whose start address is same as StartupAcm
//
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = gFitTableContext.BiosModule[Index].Address;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = Address - gFitTableContext.BiosModule[Index].Address;
gFitTableContext.BiosModuleNumber ++;
gFitTableContext.FitEntryNumber++;
}
TempSize = gFitTableContext.BiosModule[Index].Address + gFitTableContext.BiosModule[Index].Size;
gFitTableContext.BiosModule[Index].Address = Address + Size;
gFitTableContext.BiosModule[Index].Size = TempSize - gFitTableContext.BiosModule[Index].Address;
if (gFitTableContext.BiosModule[Index].Size == 0) {
//
// remove the entry if size is 0
//
for (SubIndex = Index; SubIndex < (INTN)gFitTableContext.BiosModuleNumber - 1; SubIndex ++) {
gFitTableContext.BiosModule[SubIndex].Address = gFitTableContext.BiosModule[SubIndex + 1].Address;
gFitTableContext.BiosModule[SubIndex].Size = gFitTableContext.BiosModule[SubIndex + 1].Size;
}
gFitTableContext.BiosModuleNumber --;
gFitTableContext.FitEntryNumber--;
}
break;
}
}
}
UINT8 *
GetMicrocodeBufferFromFv (
EFI_FIRMWARE_VOLUME_HEADER *FvHeader
)
{
UINT8 *MicrocodeBuffer;
EFI_FFS_FILE_HEADER *FfsHeader;
MicrocodeBuffer = NULL;
//
// Skip FV header + FV extension header + FFS header
//
FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *) FvHeader + FvHeader->HeaderLength);
while ((UINT8 *) FfsHeader < (UINT8 *) FvHeader + FvHeader->FvLength) {
if (FfsHeader->Type == EFI_FV_FILETYPE_RAW) {
//
// Find the first RAW ffs file as Microcode Buffer
//
MicrocodeBuffer = (UINT8 *)(FfsHeader + 1);
break;
}
if (GetFfsFileLength (FfsHeader) == 0xFFFFFF) {
// spare space is found, and exit
break;
}
FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + ((GetFfsFileLength (FfsHeader)+7)&~7));
}
return MicrocodeBuffer;
}
UINT32
GetFitEntryNumber (
IN INTN argc,
IN CHAR8 **argv,
IN UINT8 *FdBuffer,
IN UINT32 FdSize
)
/*++
Routine Description:
Get FIT entry number and fill global FIT table context, from argument
Arguments:
argc - Number of command line parameters.
argv - Array of pointers to parameter strings.
FdBuffer - FD binary buffer
FdSize - FD size
Returns:
FitEntryNumber - The FIT entry number
0 - Argument parse fail
*/
{
EFI_GUID Guid;
EFI_GUID MicrocodeFfsGuid;
INTN Index;
UINT8 *FileBuffer;
UINT32 FileSize;
UINT32 Type;
UINT32 SubType;
UINT8 *MicrocodeFileBuffer;
UINT8 *MicrocodeFileBufferRaw;
UINT32 MicrocodeFileSize;
UINT32 MicrocodeBase;
UINT32 MicrocodeSize;
UINT8 *MicrocodeBuffer;
UINT32 MicrocodeBufferSize;
UINT8 *Walker;
UINT32 MicrocodeRegionOffset;
UINT32 MicrocodeRegionSize;
UINT32 SlotSize;
STATUS Status;
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
UINTN FitEntryNumber;
BOOLEAN BiosInfoExist;
BOOLEAN SlotMode;
BOOLEAN SlotModeForce;
BIOS_INFO_HEADER *BiosInfo;
BIOS_INFO_STRUCT *BiosInfoStruct;
UINTN BiosInfoIndex;
SlotMode = FALSE;
SlotModeForce = FALSE;
//
// Init index
//
Index = 3;
if (((strcmp (argv[1], "-D") == 0) ||
(strcmp (argv[1], "-d") == 0)) ) {
Index ++;
}
//
// Fill Global Version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
gFitTableContext.GlobalVersion = DEFAULT_FIT_ENTRY_VERSION;
} else {
gFitTableContext.GlobalVersion = xtoi (argv[Index + 1]);
Index += 2;
}
//
// 0. FIT Header
//
gFitTableContext.FitEntryNumber = 1;
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-F") != 0) &&
(strcmp (argv[Index], "-f") != 0)) ) {
//
// Use default address
//
gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
} else {
//
// Get offset from parameter
//
gFitTableContext.FitTablePointerOffset = xtoi (argv[Index + 1]);
Index += 2;
}
//
// 0.1 FIT Header 2
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-F") != 0) &&
(strcmp (argv[Index], "-f") != 0)) ) {
//
// Bypass
//
gFitTableContext.FitTablePointerOffset2 = 0;
} else {
//
// Get offset from parameter
//
gFitTableContext.FitTablePointerOffset2 = xtoi (argv[Index + 1]);
Index += 2;
}
//
// 0.2 FIT Header version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
gFitTableContext.FitHeaderVersion = gFitTableContext.GlobalVersion;
} else {
//
// Get offset from parameter
//
gFitTableContext.FitHeaderVersion = xtoi (argv[Index + 1]);
Index += 2;
}
//
// 0.3 Microcode alignment
//
if ((Index >= argc) ||
((strcmp (argv[Index], "-NA") != 0) &&
(strcmp (argv[Index], "-na") != 0) &&
(strcmp (argv[Index], "-A") != 0) &&
(strcmp (argv[Index], "-a") != 0))) {
//
// by pass
//
gFitTableContext.MicrocodeIsAligned = TRUE;
gFitTableContext.MicrocodeAlignValue = 0x800;
} else if ((strcmp (argv[Index], "-NA") == 0) || (strcmp (argv[Index], "-na") == 0)) {
gFitTableContext.MicrocodeIsAligned = FALSE;
gFitTableContext.MicrocodeAlignValue = 1;
Index += 1;
} else if ((strcmp (argv[Index], "-A") == 0) || (strcmp (argv[Index], "-a") == 0)) {
gFitTableContext.MicrocodeIsAligned = TRUE;
//
// Get alignment from parameter
//
gFitTableContext.MicrocodeAlignValue = xtoi (argv[Index + 1]);;
Index += 2;
}
if ((Index >= argc) ||
((strcmp (argv[Index], "-REMAP") == 0) ||
(strcmp (argv[Index], "-remap") == 0)) ) {
//
// by pass
//
gFitTableContext.TopFlashAddressRemapValue = xtoi (argv[Index + 1]);
Index += 2;
} else {
//
// no remapping
//
gFitTableContext.TopFlashAddressRemapValue = 0x100000000;
}
printf ("Top Flash Address Value : 0x%llx\n", (unsigned long long) gFitTableContext.TopFlashAddressRemapValue);
//
// 0.4 Clear FIT table related memory
//
if ((Index >= argc) ||
((strcmp (argv[Index], "-CLEAR") != 0) &&
(strcmp (argv[Index], "-clear") != 0)) ) {
//
// by pass
//
gFitTableContext.Clear = FALSE;
} else {
//
// Clear FIT table
//
gFitTableContext.Clear = TRUE;
//
// Do not parse any more
//
return 0;
}
//
// 0.5 SlotSize
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-L") != 0) &&
(strcmp (argv[Index], "-l") != 0) &&
(strcmp (argv[Index], "-LF") != 0) &&
(strcmp (argv[Index], "-lf") != 0))) {
//
// Bypass
//
SlotSize = 0;
} else {
SlotSize = xtoi (argv[Index + 1]);
if (SlotSize == 0 || SlotSize & 0xF) {
printf ("Invalid slotsize = 0x%x, slot size should not be zero, or start at a non-16-byte aligned linear address!\n", SlotSize);
return 0;
}
if (strcmp (argv[Index], "-LF") == 0 || strcmp (argv[Index], "-lf") == 0) {
SlotModeForce = TRUE;
Index += 2;
} else {
SlotMode = IsGuidData(argv[Index + 2], &MicrocodeFfsGuid);
if (!SlotMode) {
printf ("Need a ffs GUID for search uCode ffs\n");
return 0;
}
Index += 3;
}
}
//
// 0.6 BiosInfo
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-I") != 0) &&
(strcmp (argv[Index], "-i") != 0)) ) {
//
// Bypass
//
BiosInfoExist = FALSE;
} else {
//
// Get offset from parameter
//
BiosInfoExist = TRUE;
if (IsGuidData (argv[Index + 1], &Guid)) {
FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
if (FileBuffer == NULL) {
Error (NULL, 0, 0, "-I Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
// not found
return 0;
}
BiosInfo = (BIOS_INFO_HEADER *)FileBuffer;
for (BiosInfoIndex = 0; BiosInfoIndex < FileSize; BiosInfoIndex++) {
if (((BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex))->Signature == BIOS_INFO_SIGNATURE) {
BiosInfo = (BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex);
}
}
if (BiosInfo->Signature != BIOS_INFO_SIGNATURE) {
Error (NULL, 0, 0, "-I Parameter incorrect, Signature Error!", NULL);
// not found
return 0;
}
BiosInfoStruct = (BIOS_INFO_STRUCT *)(BiosInfo + 1);
for (BiosInfoIndex = 0; BiosInfoIndex < BiosInfo->EntryCount; BiosInfoIndex++) {
if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT) != 0) {
continue;
}
switch (BiosInfoStruct[BiosInfoIndex].Type) {
case FIT_TABLE_TYPE_HEADER:
Error (NULL, 0, 0, "-I Parameter incorrect, Header Type unsupported!", NULL);
return 0;
case FIT_TABLE_TYPE_STARTUP_ACM:
if (gFitTableContext.StartupAcm.Type != 0) {
Error (NULL, 0, 0, "-I Parameter incorrect, Duplicated StartupAcm!", NULL);
return 0;
}
gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM;
gFitTableContext.StartupAcm.Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.StartupAcm.Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
gFitTableContext.StartupAcmVersion = BiosInfoStruct[BiosInfoIndex].Version;
gFitTableContext.FitEntryNumber ++;
break;
case FIT_TABLE_TYPE_DIAGNST_ACM:
if (gFitTableContext.DiagnstAcm.Type != 0) {
Error (NULL, 0, 0, "-U Parameter incorrect, Duplicated DiagnosticsAcm!", NULL);
return 0;
}
gFitTableContext.DiagnstAcm.Type = FIT_TABLE_TYPE_DIAGNST_ACM;
gFitTableContext.DiagnstAcm.Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.DiagnstAcm.Size = 0;
gFitTableContext.DiagnstAcmVersion = DEFAULT_FIT_ENTRY_VERSION;
gFitTableContext.FitEntryNumber ++;
break;
case FIT_TABLE_TYPE_BIOS_MODULE:
if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB) != 0) {
continue;
}
if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
Error (NULL, 0, 0, "-I Parameter incorrect, Too many Bios Module!", NULL);
return 0;
}
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
gFitTableContext.BiosModuleVersion = BiosInfoStruct[BiosInfoIndex].Version;
gFitTableContext.BiosModuleNumber ++;
gFitTableContext.FitEntryNumber ++;
break;
case FIT_TABLE_TYPE_MICROCODE:
if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION) == 0) {
if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
Error (NULL, 0, 0, "-I Parameter incorrect, Too many Microcode!", NULL);
return 0;
}
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
gFitTableContext.MicrocodeVersion = BiosInfoStruct[BiosInfoIndex].Version;
gFitTableContext.MicrocodeNumber++;
gFitTableContext.FitEntryNumber++;
} else {
MicrocodeRegionOffset = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
MicrocodeRegionSize = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
if (MicrocodeRegionOffset == 0) {
Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionOffset is 0", NULL);
return 0;
}
if (MicrocodeRegionSize == 0) {
Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize is 0", NULL);
return 0;
}
if (MicrocodeRegionSize > FdSize) {
Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize too large", NULL);
return 0;
}
MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize);
MicrocodeFileSize = MicrocodeRegionSize;
MicrocodeBase = MicrocodeRegionOffset;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
MicrocodeBuffer = GetMicrocodeBufferFromFv (FvHeader);
} else {
MicrocodeBuffer = MicrocodeFileBuffer;
}
if (SlotMode) {
MicrocodeBuffer = FindFileFromFvByGuid(MicrocodeFileBuffer, MicrocodeFileSize, &MicrocodeFfsGuid, &MicrocodeBufferSize);
if (MicrocodeBuffer == NULL) {
printf ("-L Parameter incorrect, GUID not found\n");
// not found
return 0;
}
}
while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) {
if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
break;
}
if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
break;
}
if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
MicrocodeSize = 2048;
} else {
//
// MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment.
//
if (gFitTableContext.MicrocodeIsAligned) {
if (gFitTableContext.MicrocodeAlignValue & 0xF) {
printf ("-A Parameter incorrect, Microcode data must start at a 16-byte aligned linear address!\n");
return 0;
}
MicrocodeSize = ROUNDUP (*(UINT32 *)(MicrocodeBuffer + 32), gFitTableContext.MicrocodeAlignValue);
} else {
MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
}
}
//
// Add Microcode
//
if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
printf ("-I Parameter incorrect, Too many Microcode!\n");
return 0;
}
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + (UINT32)((UINTN) MicrocodeBuffer - (UINTN) MicrocodeFileBuffer);
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
gFitTableContext.MicrocodeNumber++;
gFitTableContext.FitEntryNumber++;
if (SlotSize != 0) {
if (SlotSize < MicrocodeSize) {
printf ("Parameter incorrect, Slot size: %x is too small for Microcode size: %x!\n", SlotSize, MicrocodeSize);
return 0;
}
MicrocodeBuffer += SlotSize;
} else {
MicrocodeBuffer += MicrocodeSize;
}
}
///
/// Check the remaining buffer
///
if (((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) && (SlotMode || SlotModeForce)) {
for (Walker = MicrocodeBuffer; Walker < MicrocodeFileBuffer + MicrocodeFileSize; Walker++) {
if (*Walker != 0xFF) {
printf ("Error: detect non-spare space after uCode array, please check uCode array!\n");
return 0;
}
}
///
/// Split the spare space as empty buffer for save uCode patch.
///
while (MicrocodeBuffer + SlotSize <= MicrocodeFileBuffer + MicrocodeFileSize) {
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + (UINT32)((UINTN) MicrocodeBuffer - (UINTN) MicrocodeFileBuffer);
gFitTableContext.MicrocodeNumber++;
gFitTableContext.FitEntryNumber++;
MicrocodeBuffer += SlotSize;
}
}
}
break;
case FIT_TABLE_TYPE_TPM_POLICY:
case FIT_TABLE_TYPE_BIOS_POLICY:
case FIT_TABLE_TYPE_TXT_POLICY:
case FIT_TABLE_TYPE_KEY_MANIFEST:
case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
case FIT_TABLE_TYPE_BIOS_DATA_AREA:
case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
default :
if (BiosInfoStruct[BiosInfoIndex].Version != 0) {
if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) {
Error (NULL, 0, 0, "-I Parameter incorrect, Too many Optional Module!", NULL);
return 0;
}
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = BiosInfoStruct[BiosInfoIndex].Type;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version;
gFitTableContext.OptionalModuleNumber++;
gFitTableContext.FitEntryNumber++;
} else {
if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
Error (NULL, 0, 0, "-I Parameter incorrect, Too many Port Module!", NULL);
return 0;
}
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = BiosInfoStruct[BiosInfoIndex].Type;
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT32)(BiosInfoStruct[BiosInfoIndex].Address >> 32);
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version;
gFitTableContext.PortModuleNumber++;
gFitTableContext.FitEntryNumber++;
}
break;
}
}
} else {
Error (NULL, 0, 0, "-I Parameter incorrect, expect GUID!", NULL);
return 0;
}
Index += 2;
}
//
// 1. StartupAcm
//
do {
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-S") != 0) &&
(strcmp (argv[Index], "-s") != 0)) ) {
if (BiosInfoExist && (gFitTableContext.StartupAcm.Type == FIT_TABLE_TYPE_STARTUP_ACM)) {
break;
}
// Error (NULL, 0, 0, "-S Parameter incorrect, expect -S!", NULL);
// return 0;
printf ("-S not found. WARNING!\n");
break;
}
if (IsGuidData (argv[Index + 1], &Guid)) {
FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
if (FileBuffer == NULL) {
Error (NULL, 0, 0, "-S Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
// not found
return 0;
}
FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
Index += 2;
} else {
if (Index + 2 >= argc) {
Error (NULL, 0, 0, "-S Parameter incorrect, expect Address Size!", NULL);
return 0;
}
FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
FileSize = xtoi (argv[Index + 2]);
Index += 3;
}
if (gFitTableContext.StartupAcm.Type != 0) {
Error (NULL, 0, 0, "-S Parameter incorrect, Duplicated StartupAcm!", NULL);
return 0;
}
gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM;
gFitTableContext.StartupAcm.Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.StartupAcm.Size = FileSize;
gFitTableContext.FitEntryNumber ++;
//
// 1.1 StartupAcm version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
gFitTableContext.StartupAcmVersion = gFitTableContext.GlobalVersion;
} else {
//
// Get offset from parameter
//
gFitTableContext.StartupAcmVersion = xtoi (argv[Index + 1]);
Index += 2;
}
} while (FALSE);
//
// 1.5. DiagnosticsAcm
//
do {
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-U") != 0) &&
(strcmp (argv[Index], "-u") != 0)) ) {
if (BiosInfoExist && (gFitTableContext.DiagnstAcm.Type == FIT_TABLE_TYPE_DIAGNST_ACM)) {
break;
}
break;
}
if (IsGuidData (argv[Index + 1], &Guid)) {
FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
if (FileBuffer == NULL) {
Error (NULL, 0, 0, "-U Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
return 0;
}
FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
Index += 2;
} else {
FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
Index += 2;
}
if (gFitTableContext.DiagnstAcm.Type != 0) {
Error (NULL, 0, 0, "-U Parameter incorrect, Duplicated DiagnosticsAcm!", NULL);
return 0;
}
gFitTableContext.DiagnstAcm.Type = FIT_TABLE_TYPE_DIAGNST_ACM;
gFitTableContext.DiagnstAcm.Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.DiagnstAcm.Size = 0;
gFitTableContext.FitEntryNumber ++;
gFitTableContext.DiagnstAcmVersion = DEFAULT_FIT_ENTRY_VERSION;
} while (FALSE);
// 2. BiosModule
//
do {
if ((Index + 2 >= argc) ||
((strcmp (argv[Index], "-B") != 0) &&
(strcmp (argv[Index], "-b") != 0)) ) {
if (BiosInfoExist && (gFitTableContext.BiosModuleNumber != 0)) {
break;
}
// Error (NULL, 0, 0, "-B Parameter incorrect, expect -B!", NULL);
// return 0;
printf ("-B not found. WARNING!\n");
break;
}
FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
FileSize = xtoi (argv[Index + 2]);
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize;
gFitTableContext.BiosModuleNumber ++;
gFitTableContext.FitEntryNumber ++;
while (TRUE) {
Index += 3;
if (Index + 2 >= argc) {
break;
}
if ((strcmp (argv[Index], "-B") != 0) &&
(strcmp (argv[Index], "-b") != 0) ) {
break;
}
if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
Error (NULL, 0, 0, "-B Parameter incorrect, Too many Bios Module!", NULL);
return 0;
}
FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
FileSize = xtoi (argv[Index + 2]);
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize;
gFitTableContext.BiosModuleNumber ++;
gFitTableContext.FitEntryNumber++;
}
//
// 2.1 BiosModule version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
gFitTableContext.BiosModuleVersion = gFitTableContext.GlobalVersion;
} else {
//
// Get offset from parameter
//
gFitTableContext.BiosModuleVersion = xtoi (argv[Index + 1]);
Index += 2;
}
} while (FALSE);
//
// 3. Microcode
//
while (TRUE) {
if (Index + 1 >= argc) {
break;
}
if ((strcmp (argv[Index], "-M") != 0) &&
(strcmp (argv[Index], "-m") != 0) ) {
break;
}
if (IsGuidData (argv[Index + 2], &Guid)) {
Error (NULL, 0, 0, "-M Parameter incorrect, GUID unsupported!", NULL);
return 0;
} else {
if (Index + 2 >= argc) {
break;
}
FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
FileSize = xtoi (argv[Index + 2]);
Index += 3;
}
if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
Error (NULL, 0, 0, "-M Parameter incorrect, Too many Microcode!", NULL);
return 0;
}
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = FileSize;
gFitTableContext.MicrocodeNumber++;
gFitTableContext.FitEntryNumber++;
}
//
// 3.1 MicrocodeFv
//
while (TRUE) {
if (Index + 1 >= argc) {
break;
}
if ((strcmp (argv[Index], "-U") != 0) &&
(strcmp (argv[Index], "-u") != 0) ) {
break;
}
//
// Get Fv
//
if (IsGuidData (argv[Index + 1], &Guid)) {
MicrocodeFileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &MicrocodeFileSize);
if (MicrocodeFileBuffer == NULL) {
Error (NULL, 0, 0, "-U Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
// not found
return 0;
}
Index += 2;
MicrocodeBuffer = MicrocodeFileBuffer;
MicrocodeFileBufferRaw = NULL;
MicrocodeRegionOffset = MEMORY_TO_FLASH (MicrocodeFileBuffer, FdBuffer, FdSize);
MicrocodeRegionSize = 0;
MicrocodeBase = MicrocodeRegionOffset;
} else {
if (Index + 2 >= argc) {
break;
}
Status = ReadInputFile (argv[Index + 1], &MicrocodeFileBuffer, &MicrocodeFileSize, &MicrocodeFileBufferRaw);
if (Status != STATUS_SUCCESS) {
MicrocodeRegionOffset = xtoi (argv[Index + 1]);
MicrocodeRegionSize = xtoi (argv[Index + 2]);
if (MicrocodeRegionOffset == 0) {
Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionOffset is 0, or unable to open file", "%s", argv[Index + 1]);
return 0;
}
if (MicrocodeRegionSize == 0) {
Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize is 0", NULL);
return 0;
}
if (MicrocodeRegionSize > FdSize) {
Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize too large", NULL);
return 0;
}
Index += 3;
MicrocodeFileBufferRaw = NULL;
MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize);
MicrocodeFileSize = MicrocodeRegionSize;
MicrocodeBase = MicrocodeRegionOffset;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
MicrocodeBuffer = GetMicrocodeBufferFromFv (FvHeader);
} else {
MicrocodeBuffer = MicrocodeFileBuffer;
}
} else {
MicrocodeBase = xtoi (argv[Index + 2]);
Index += 3;
MicrocodeRegionOffset = 0;
MicrocodeRegionSize = 0;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
MicrocodeBuffer = GetMicrocodeBufferFromFv (FvHeader);
} else {
MicrocodeBuffer = MicrocodeFileBuffer;
}
}
}
while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) {
if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
break;
}
if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
break;
}
if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
MicrocodeSize = 2048;
} else {
//
// MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment.
//
if (gFitTableContext.MicrocodeIsAligned) {
MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) + (gFitTableContext.MicrocodeAlignValue - 1)) & ~(gFitTableContext.MicrocodeAlignValue - 1);
} else {
MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
}
}
//
// Add Microcode
//
if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
printf ("-U Parameter incorrect, Too many Microcode!\n");
return 0;
}
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + (UINT32)((UINTN) MicrocodeBuffer - (UINTN) MicrocodeFileBuffer);
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
gFitTableContext.MicrocodeNumber++;
gFitTableContext.FitEntryNumber++;
MicrocodeBuffer += MicrocodeSize;
}
if (MicrocodeFileBufferRaw != NULL) {
free ((VOID *)MicrocodeFileBufferRaw);
MicrocodeFileBufferRaw = NULL;
}
}
//
// 3.3 Microcode version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
gFitTableContext.MicrocodeVersion = gFitTableContext.GlobalVersion;
} else {
//
// Get offset from parameter
//
gFitTableContext.MicrocodeVersion = xtoi (argv[Index + 1]);
Index += 2;
}
//
// 4. Optional type
//
while (TRUE) {
if (Index + 2 >= argc) {
break;
}
if ((strcmp (argv[Index], "-O") != 0) &&
(strcmp (argv[Index], "-o") != 0) ) {
break;
}
Type = xtoi (argv[Index + 1]);
//
// 1st, try CSE entry sub-type
//
SubType = 0;
if (Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) {
if (Index + 3 >= argc) {
break;
}
SubType = xtoi (argv[Index + 2]);
//
// try file
//
if (SubType != FIT_TABLE_SUBTYPE_FIT_PATCH_MANIFEST && SubType != FIT_TABLE_SUBTYPE_ACM_MANIFEST) {
Error (NULL, 0, 0, "-O Parameter incorrect, SubType unsupported!", NULL);
return 0;
}
Status = ReadInputFile (argv[Index + 3], &FileBuffer, &FileSize, NULL);
if (Status == STATUS_SUCCESS) {
if (FileSize >= 0x80000000) {
Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
free (FileBuffer);
return 0;
}
//
// Set the most significant bit
// It means the data in memory, not in flash yet.
// Assume the file size should < 2G.
//
FileSize |= 0x80000000;
Index += 4;
} else {
if (Status == STATUS_WARNING) {
Error (NULL, 0, 0, "-O Parameter incorrect, Unable to open file", argv[Index + 3]);
}
return 0;
}
} else {
//
// 2nd, try GUID
//
if (IsGuidData (argv[Index + 2], &Guid)) {
FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
if (FileBuffer == NULL) {
Error (NULL, 0, 0, "-O Parameter incorrect, GUID not found!", "%s", argv[Index + 2]);
// not found
return 0;
}
if (FileSize >= 0x80000000) {
Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
return 0;
}
FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
Index += 3;
} else {
//
// 3rd, try file
//
Status = ReadInputFile (argv[Index + 2], &FileBuffer, &FileSize, NULL);
if (Status == STATUS_SUCCESS) {
if (FileSize >= 0x80000000) {
Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
free (FileBuffer);
return 0;
}
//
// Set the most significant bit
// It means the data in memory, not in flash yet.
// Assume the file size should < 2G.
//
FileSize |= 0x80000000;
Index += 3;
} else {
//
// 4th, try
//
if (Index + 3 >= argc) {
break;
}
if ((strcmp (argv[Index + 2], "RESERVE") == 0) ||
(strcmp (argv[Index + 2], "reserve") == 0)) {
FileSize = xtoi (argv[Index + 3]);
if (FileSize >= 0x80000000) {
Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
return 0;
}
FileBuffer = malloc (FileSize);
if (FileBuffer == NULL) {
Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
return 0;
}
SetMem (FileBuffer, FileSize, 0xFF);
//
// Set the most significant bit
// It means the data in memory, not in flash yet.
// Assume the file size should < 2G.
//
FileSize |= 0x80000000;
Index += 4;
} else {
//
// 5th, try
//
if (Index + 3 >= argc) {
break;
}
FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 2]);
FileSize = xtoi (argv[Index + 3]);
if (FileSize >= 0x80000000) {
Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
return 0;
}
Index += 4;
}
}
}
}
if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) {
Error (NULL, 0, 0, "-O Parameter incorrect, Too many Optional Module!", NULL);
free (FileBuffer);
return 0;
}
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = Type;
if (gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) {
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].SubType = SubType;
}
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Buffer = FileBuffer;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = FileSize;
//
// 4.1 Optional Module version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = gFitTableContext.GlobalVersion;
} else {
//
// Get offset from parameter
//
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = xtoi (argv[Index + 1]);
Index += 2;
}
gFitTableContext.OptionalModuleNumber ++;
gFitTableContext.FitEntryNumber++;
}
//
// 5. Port type
//
while (TRUE) {
if (Index + 6 >= argc) {
break;
}
if ((strcmp (argv[Index], "-P") != 0) &&
(strcmp (argv[Index], "-p") != 0) ) {
break;
}
Type = xtoi (argv[Index + 1]);
if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
printf ("-P Parameter incorrect, Too many Port Module!\n");
return 0;
}
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = Type;
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT16)xtoi (argv[Index + 2]) + ((UINT16)xtoi (argv[Index + 3]) << 16);
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT8)xtoi (argv[Index + 4]) + ((UINT8)xtoi (argv[Index + 5]) << 8) + ((UINT16)xtoi (argv[Index + 6]) << 16);
Index += 7;
//
// 5.1 Port Module version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = 0;
} else {
//
// Get offset from parameter
//
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = xtoi (argv[Index + 1]);
Index += 2;
}
gFitTableContext.PortModuleNumber++;
gFitTableContext.FitEntryNumber++;
}
//
// Final: Check StartupAcm in BiosModule.
//
CheckOverlap (gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size);
FitEntryNumber = gFitTableContext.FitEntryNumber;
for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) {
if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
// NOTE: It might be virtual address now. Just put a place holder.
FitEntryNumber ++;
}
}
return FitEntryNumber;
}
VOID *
FindSpaceSkipApVector (
IN UINT8 *FvBuffer,
IN UINT8 *Address,
IN UINTN Size
)
/*++
Routine Description:
No enough space - it might happen that it is occupied by AP wake vector.
Last chance - skip this and search again.
Arguments:
FvBuffer - FvRecovery binary buffer
Address - Address to be searched from
Size - Size need to be filled
Returns:
FitTableOffset - The FIT table offset
NULL - No enough space for FIT table
*/
{
UINT8 *ApVector;
UINT8 *NewAddress;
UINTN Index;
ApVector = (UINT8 *)((UINTN)Address & ~0xFFF);
if ((UINTN)ApVector <= (UINTN)FvBuffer) {
return NULL;
}
NewAddress = (UINT8 *)(ApVector - Size);
for (Index = 0; Index < Size; Index ++) {
if (NewAddress[Index] != 0xFF) {
return NULL;
}
}
return NewAddress;
}
VOID *
GetFreeSpaceFromFv (
IN UINT8 *FvBuffer,
IN UINT32 FvSize,
IN UINT32 FitEntryNumber
)
/*++
Routine Description:
Get free space for FIT table from FvRecovery
Arguments:
FvBuffer - FvRecovery binary buffer
FvSize - FvRecovery size
FitEntryNumber - The FIT entry number
Returns:
FitTableOffset - The offset of FIT table in FvRecovery file
NULL - Free space not found
--*/
{
UINT8 *FitTableOffset;
INTN Index;
INTN SubIndex;
UINT8 *OptionalModuleAddress;
EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
UINT32 AlignedSize;
UINT32 FitTableSize;
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
EFI_FFS_FILE_HEADER *FileHeader;
UINT64 FvLength;
UINT32 Offset;
UINT32 FileLength;
UINT32 FileOccupiedSize;
//
// Check 4G - FitTablePointerOffset
//
if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xFFFFFFFFFFFFFFFFull) &&
(*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0) &&
(*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xEEEEEEEEEEEEEEEEull)) {
Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
return NULL;
}
if (gFitTableContext.FitTablePointerOffset2 != 0) {
if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xFFFFFFFFFFFFFFFFull) &&
(*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0) &&
(*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xEEEEEEEEEEEEEEEEull)) {
Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
return NULL;
}
}
//
// Get EFI_FFS_VOLUME_TOP_FILE_GUID location
//
FitTableOffset = NULL;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvBuffer;
FvLength = FvHeader->FvLength;
FileHeader = (EFI_FFS_FILE_HEADER *)(FvBuffer + FvHeader->HeaderLength);
Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
while (Offset < FvLength) {
FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
if ((CompareGuid (&(FileHeader->Name), &VTFGuid)) == 0) {
// find it
FitTableOffset = (UINT8 *)FileHeader;
break;
}
FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize);
Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
}
if (FitTableOffset == NULL) {
Error (NULL, 0, 0, "EFI_FFS_VOLUME_TOP_FILE_GUID not found!", NULL);
return NULL;
}
FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
FitTableSize += FIT_ALIGNMENT;
FitTableSize &= ~FIT_ALIGNMENT;
FitTableOffset = (UINT8 *)((UINTN)FitTableOffset & ~FIT_ALIGNMENT);
FitTableOffset = (UINT8 *)(FitTableOffset - FitTableSize);
//
// Check it
//
for (Index = 0; Index < (INTN)(FitTableSize); Index ++) {
if (FitTableOffset[Index] != 0xFF) {
//
// No enough space - it might happen that it is occupied by AP wake vector.
// Last chance - skip this and search again.
//
FitTableOffset = FindSpaceSkipApVector (FvBuffer, &FitTableOffset[Index], FitTableSize);
if (FitTableOffset == NULL) {
Error (NULL, 0, 0, "No enough space for FIT table!", NULL);
return NULL;
}
}
}
//
// Check space for Optional module
//
OptionalModuleAddress = FitTableOffset;
for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) {
AlignedSize = gFitTableContext.OptionalModule[Index].Size;
if ((gFitTableContext.OptionalModule[Index].Size & 0x80000000) != 0) {
//
// Need copy binary to file.
//
gFitTableContext.OptionalModule[Index].Size &= ~0x80000000;
AlignedSize = gFitTableContext.OptionalModule[Index].Size;
if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
// Let it 64 byte align
AlignedSize += BIOS_MODULE_ALIGNMENT;
AlignedSize &= ~BIOS_MODULE_ALIGNMENT;
}
OptionalModuleAddress -= AlignedSize;
if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
// Let it 64 byte align
OptionalModuleAddress = (UINT8 *)((UINTN)OptionalModuleAddress & ~BIOS_MODULE_ALIGNMENT);
}
for (SubIndex = 0; SubIndex < (INTN)(AlignedSize); SubIndex ++) {
if (OptionalModuleAddress[SubIndex] != 0xFF) {
//
// No enough space - it might happen that it is occupied by AP wake vector.
// Last chance - skip this and search again.
//
OptionalModuleAddress = FindSpaceSkipApVector (FvBuffer, &OptionalModuleAddress[SubIndex], AlignedSize);
if (OptionalModuleAddress == NULL) {
Error (NULL, 0, 0, "No enough space for OptionalModule!", NULL);
return NULL;
}
}
}
memcpy (OptionalModuleAddress, gFitTableContext.OptionalModule[Index].Buffer, gFitTableContext.OptionalModule[Index].Size);
free (gFitTableContext.OptionalModule[Index].Buffer);
gFitTableContext.OptionalModule[Index].Address = MEMORY_TO_FLASH (OptionalModuleAddress, FvBuffer, FvSize);
}
//
// Final: Check BiosPolicyData in BiosModule.
//
if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
CheckOverlap (gFitTableContext.OptionalModule[Index].Address, AlignedSize);
}
}
return FitTableOffset;
}
VOID
PrintFitData (
VOID
)
/*++
Routine Description:
Output FIT table information
Arguments:
None
Returns:
None
--*/
{
UINT32 Index;
printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset);
if (gFitTableContext.FitTablePointerOffset2 != 0) {
printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset2);
}
printf ("Total FIT Entry number: 0x%x\n", gFitTableContext.FitEntryNumber);
printf ("FitHeader version: 0x%04x\n", gFitTableContext.FitHeaderVersion);
if (gFitTableContext.StartupAcm.Address != 0) {
printf ("StartupAcm - (0x%08x, 0x%08x, 0x%04x)\n", gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size, gFitTableContext.StartupAcmVersion);
}
if (gFitTableContext.DiagnstAcm.Address != 0) {
printf ("DiagnosticAcm - (0x%08x, 0x%08x, 0x%04x)\n", gFitTableContext.DiagnstAcm.Address, gFitTableContext.DiagnstAcm.Size, gFitTableContext.DiagnstAcmVersion);
}
for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
printf ("BiosModule[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.BiosModule[Index].Address, gFitTableContext.BiosModule[Index].Size, gFitTableContext.BiosModuleVersion);
}
for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
printf ("Microcode[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.Microcode[Index].Address, gFitTableContext.Microcode[Index].Size, gFitTableContext.MicrocodeVersion);
}
for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) {
printf ("OptionalModule[%d] - (0x%08x, 0x%08x, 0x%02x, 0x%04x)\n", Index, gFitTableContext.OptionalModule[Index].Address, gFitTableContext.OptionalModule[Index].Size, gFitTableContext.OptionalModule[Index].Type, gFitTableContext.OptionalModule[Index].Version);
}
for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
printf ("PortModule[%d] - (0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%04x, 0x%02x, 0x%04x)\n", Index,
(UINT16)gFitTableContext.PortModule[Index].Address, (UINT16)(gFitTableContext.PortModule[Index].Address >> 16),
(UINT8)gFitTableContext.PortModule[Index].Size, (UINT8)(gFitTableContext.PortModule[Index].Size >> 8), (UINT16)(gFitTableContext.PortModule[Index].Size >> 16),
gFitTableContext.PortModule[Index].Type, gFitTableContext.PortModule[Index].Version);
}
printf ("\n");
return ;
}
CHAR8 *mFitCseSubTypeStr[] = {
"CSE_RSVD ",
"CSE_K_HASH1",
"CSE_M_HASH ",
"CSE_BPOLICY",
"CSE_OTHR_BP",
"CSE_OEMSMIP",
"CSE_MRCDATA",
"CSE_IBBL_H ",
"CSE_IBB_H ",
"CSE_OEM_ID ",
"CSEOEMSKUID",
"CSE_BD_IND ",
"CSE_FPM ",
"CSE_ACMM "
};
CHAR8 *mFitTypeStr[] = {
" ",
"MICROCODE ",
"STARTUP_ACM",
"DIAGNST_ACM",
" ",
" ",
" ",
" ",
"BIOS_MODULE",
"TPM_POLICY ",
"BIOS_POLICY",
"TXT_POLICY ",
"KEYMANIFEST",
"BP_MANIFEST",
"BIOS_DATA_A",
" ",
" ",
"CSE_SECUREB"
};
CHAR8 mFitSignature[] = "'_FIT_ ' ";
CHAR8 mFitSignatureInHeader[] = "' ' ";
CHAR8 *
FitTypeToStr (
IN FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry
)
/*++
Routine Description:
Convert FitEntry type to a string
Arguments:
FitEntry - Fit entry
Returns:
String
--*/
{
if (FitEntry->Type == FIT_TABLE_TYPE_HEADER) {
CopyMem (&mFitSignatureInHeader[1], &FitEntry->Address, sizeof(FitEntry->Address));
return mFitSignatureInHeader;
}
if (FitEntry->Type < sizeof (mFitTypeStr)/sizeof(mFitTypeStr[0])) {
if (FitEntry->Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) {
//
// "Reserved" field is used to distinguish CSE Secure Boot entries (see FIT spec revision 1.2)
//
if (FitEntry->Rsvd < sizeof (mFitCseSubTypeStr)/sizeof(mFitCseSubTypeStr[0])) {
return mFitCseSubTypeStr[FitEntry->Rsvd];
}
}
return mFitTypeStr[FitEntry->Type];
} else {
return " ";
}
}
VOID
PrintFitTable (
IN UINT8 *FvBuffer,
IN UINT32 FvSize
)
/*++
Routine Description:
Print Fit table in flash image
Arguments:
FvBuffer - FvRecovery binary buffer
FvSize - FvRecovery size
Returns:
None
--*/
{
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
UINT32 EntryNum;
UINT32 Index;
UINT32 FitTableOffset;
FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *FitEntryPort;
printf ("##############\n");
printf ("# FIT Table: #\n");
printf ("##############\n");
printf ("FIT Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset);
FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
printf ("FIT Table Address: 0x%x\n", FitTableOffset);
FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
//
// Check FitEntry is 16 byte aligned
//
if (((UINTN)FitEntry & 0xF) != 0) {
printf("ERROR: invalid FitEntry address 0x%X!\n", (UINT32) (UINTN) FitEntry);
return;
}
EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
printf ("Index: Address Size Version Type C_V Checksum (Index Data Width Bit Offset)\n");
printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
for (Index = 0; Index < EntryNum; Index++) {
printf (" %02d: %016llx %06x %04x %02x-%s %02x %02x ",
Index,
(unsigned long long) FitEntry[Index].Address,
*(UINT32 *)(&FitEntry[Index].Size[0]) & 0xFFFFFF,
FitEntry[Index].Version,
FitEntry[Index].Type,
FitTypeToStr(&FitEntry[Index]),
FitEntry[Index].C_V,
FitEntry[Index].Checksum
);
if (Index == 0) {
if (FitEntry[Index].Type != FIT_TABLE_TYPE_HEADER) {
printf("ERROR: FIT Entry 0 is not Header Type %d!\n", FIT_TABLE_TYPE_HEADER);
return;
}
if (strcmp(mFitSignatureInHeader, mFitSignature) != 0) {
printf("ERROR: FIT Entry 0 signature invalid (%s, expected %s)!\n", mFitSignatureInHeader, mFitSignature);
return;
}
}
switch (FitEntry[Index].Type) {
case FIT_TABLE_TYPE_TPM_POLICY:
case FIT_TABLE_TYPE_TXT_POLICY:
if (FitEntry[Index].Version == 0) {
FitEntryPort = (FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *)&FitEntry[Index];
printf (" ( %04x %04x %02x %02x %04x )\n",
FitEntryPort->IndexPort,
FitEntryPort->DataPort,
FitEntryPort->Width,
FitEntryPort->Bit,
FitEntryPort->Index
);
break;
}
// Not Port Configure, pass through
default:
printf ("\n");
break;
}
}
printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
printf ("Index: Address Size Version Type C_V Checksum (Index Data Width Bit Offset)\n");
printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
}
/**
This function dump raw data.
@param Data raw data
@param Size raw data size
**/
VOID
DumpData (
IN UINT8 *Data,
IN UINT32 Size
)
{
UINT32 Index;
for (Index = 0; Index < Size; Index++) {
printf ("%02x", Data[Index]);
}
}
/**
This function dump raw data with colume format.
@param Data raw data
@param Size raw data size
**/
VOID
DumpHex (
IN UINT8 *Data,
IN UINT32 Size
)
{
UINT32 Index;
UINT32 Count;
UINT32 Left;
#define COLUME_SIZE (16 * 2)
Count = Size / COLUME_SIZE;
Left = Size % COLUME_SIZE;
for (Index = 0; Index < Count; Index++) {
printf ("%04x: ", Index * COLUME_SIZE);
DumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
printf ("\n");
}
if (Left != 0) {
printf ("%04x: ", Index * COLUME_SIZE);
DumpData (Data + Index * COLUME_SIZE, Left);
printf ("\n");
}
}
//
// This table defines the ACM type string
//
CHAR8 *mAcmTypeStr[] = {
"BIOS ACM",
"SINIT ACM",
};
//
// This table defines the ACM capability string
//
CHAR8 *mCapabilityStr[] = {
"GETSEC[WAKEUP] for RLP ",
"MONITOR address for RLP ",
"ECX for MLE PageTable ",
"STM support ",
};
VOID
DumpAcm (
IN ACM_FORMAT *Acm
)
/*++
Routine Description:
DumpAcm information
Arguments:
Acm - ACM buffer
Returns:
None
--*/
{
CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
CHIPSET_ID_LIST *ChipsetIdList;
PROCESSOR_ID_LIST *ProcessorIdList;
UINT32 Index;
UINT8 *Buffer;
printf (
"*****************************************************************************\n"
"* ACM *\n"
"*****************************************************************************\n"
);
printf ("ACM: (%08x)\n", (UINT32) (UINTN) Acm);
printf (" ModuleType - %04x\n", Acm->ModuleType);
if (Acm->ModuleType == ACM_MODULE_TYPE_CHIPSET_ACM) {
printf (" Chipset ACM\n");
}
printf (" ModuleSubType - %04x\n", Acm->ModuleSubType);
if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET) != 0) {
printf (" Capable of be Executed at Reset\n");
}
if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) != 0) {
printf (" AnC Module\n");
}
printf (" HeaderLen - %08x\n", Acm->HeaderLen);
printf (" HeaderVersion - %08x\n", Acm->HeaderVersion);
printf (" ChipsetID - %04x\n", Acm->ChipsetID);
printf (" Flags - %04x\n", Acm->Flags);
printf (" PreProduction - %04x\n", Acm->Flags & ACM_MODULE_FLAG_PREPRODUCTION);
printf (" Debug Signed - %04x\n", Acm->Flags & ACM_MODULE_FLAG_DEBUG_SIGN);
printf (" ModuleVendor - %08x\n", Acm->ModuleVendor);
printf (" Date - %08x\n", Acm->Date);
printf (" Size - %08x\n", Acm->Size);
printf (" TxtSvn - %04x\n", Acm->TxtSvn);
printf (" SeSvn - %04x\n", Acm->SeSvn);
printf (" CodeControl - %08x\n", Acm->CodeControl);
printf (" ErrorEntryPoint - %08x\n", Acm->ErrorEntryPoint);
printf (" GDTLimit - %08x\n", Acm->GDTLimit);
printf (" GDTBasePtr - %08x\n", Acm->GDTBasePtr);
printf (" SegSel - %08x\n", Acm->SegSel);
printf (" EntryPoint - %08x\n", Acm->EntryPoint);
printf (" KeySize - %08x\n", Acm->KeySize);
printf (" ScratchSize - %08x\n", Acm->ScratchSize);
Buffer = (UINT8 *)(Acm + 1);
printf (" RSAPubKey - \n");
DumpHex (Buffer, Acm->KeySize * 4);
printf ("\n");
Buffer += Acm->KeySize * 4;
//
// To simplify the tool and making it independent of ACM header change,
// the rest of ACM parsing will be skipped starting ACM_HEADER_VERSION4
//
if((Acm->HeaderVersion != ACM_HEADER_VERSION_3) && (Acm->HeaderVersion != ACM_HEADER_VERSION_0)){
printf (
"*****************************************************************************\n\n"
);
return;
}
if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
printf (" RSASig - \n");
DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE); // PKCS #1.5 RSA Signature
printf ("\n");
Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
} else {
printf (" RSAPubExp - %08x\n", *(UINT32 *)Buffer);
Buffer += 4;
printf (" RSASig - \n");
DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE); // PKCS #1.5 RSA Signature
printf ("\n");
Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
}
Buffer += Acm->ScratchSize * 4;
if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) {
ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer;
printf ("Chipset ACM info:\n");
printf (
" Guid - {%08x-%08x-%08x-%08x}\n",
ChipsetAcmInformationTable->Guid.Guid0,
ChipsetAcmInformationTable->Guid.Guid1,
ChipsetAcmInformationTable->Guid.Guid2,
ChipsetAcmInformationTable->Guid.Guid3
);
printf (" ChipsetACMType - %02x\n", ChipsetAcmInformationTable->ChipsetACMType);
if (ChipsetAcmInformationTable->ChipsetACMType < sizeof(mAcmTypeStr)/sizeof(mAcmTypeStr[0])) {
printf (" %s\n", mAcmTypeStr[ChipsetAcmInformationTable->ChipsetACMType]);
}
printf (" Version - %02x\n", ChipsetAcmInformationTable->Version);
printf (" Length - %04x\n", ChipsetAcmInformationTable->Length);
printf (" ChipsetIDList - %08x\n", ChipsetAcmInformationTable->ChipsetIDList);
printf (" OsSinitTableVer - %08x\n", ChipsetAcmInformationTable->OsSinitTableVer);
printf (" MinMleHeaderVer - %08x\n", ChipsetAcmInformationTable->MinMleHeaderVer);
if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
printf (" Capabilities - %08x\n", ChipsetAcmInformationTable->Capabilities);
for (Index = 0; Index < sizeof(mCapabilityStr)/sizeof(mCapabilityStr[0]); Index++) {
if (mCapabilityStr[Index] == NULL) {
continue;
}
printf (
" %s- %08x\n",
mCapabilityStr[Index],
(ChipsetAcmInformationTable->Capabilities & (1 << Index))
);
}
printf (" AcmVersion - %02x\n", ChipsetAcmInformationTable->AcmVersion);
printf (" AcmRevision - %02x.%02x.%02x\n", ChipsetAcmInformationTable->AcmRevision[0], ChipsetAcmInformationTable->AcmRevision[1], ChipsetAcmInformationTable->AcmRevision[2]);
}
if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
printf (" ProcessorIDList - %08x\n", ChipsetAcmInformationTable->ProcessorIDList);
}
ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList);
printf ("Chipset ID List info:\n");
printf (" Count - %08x\n", ChipsetIdList->Count);
for (Index = 0; Index < ChipsetIdList->Count; Index++) {
printf (" ID[%d]:\n", Index);
printf (" Flags - %08x\n", ChipsetIdList->ChipsetID[Index].Flags);
printf (" RevisionIdMask - %08x\n", ChipsetIdList->ChipsetID[Index].Flags & ACM_CHIPSET_ID_REVISION_ID_MAKE);
printf (" VendorID - %04x\n", ChipsetIdList->ChipsetID[Index].VendorID);
printf (" DeviceID - %04x\n", ChipsetIdList->ChipsetID[Index].DeviceID);
printf (" RevisionID - %04x\n", ChipsetIdList->ChipsetID[Index].RevisionID);
}
if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
goto End;
}
ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList);
printf ("Processor ID List info:\n");
printf (" Count - %08x\n", ProcessorIdList->Count);
for (Index = 0; Index < ProcessorIdList->Count; Index++) {
printf (" ID[%d]:\n", Index);
printf (" FMS - %08x\n", ProcessorIdList->ProcessorID[Index].FMS);
printf (" FMSMask - %08x\n", ProcessorIdList->ProcessorID[Index].FMSMask);
printf (" PlatformID - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformID);
printf (" PlatformMask - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformMask);
}
}
End:
printf (
"*****************************************************************************\n\n"
);
}
BOOLEAN
CheckAcm (
IN ACM_FORMAT *Acm,
IN UINTN AcmMaxSize
)
/*++
Routine Description:
Check Acm information
Arguments:
Acm - ACM buffer
AcmMaxSize - ACM max size
Returns:
TRUE - ACM is valid
FALSE - ACM is invalid
--*/
{
CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
CHIPSET_ID_LIST *ChipsetIdList;
PROCESSOR_ID_LIST *ProcessorIdList;
UINT8 *Buffer;
if (Acm->ModuleType != ACM_MODULE_TYPE_CHIPSET_ACM) {
printf ("ACM invalid : ModuleType!\n");
return FALSE;
}
if (Acm->Size * 4 > AcmMaxSize) {
printf ("ACM invalid : Size!\n");
return FALSE;
}
//
// To simplify the tool and making it independent of ACM header change,
// the following check will be skipped starting ACM_HEADER_VERSION3
//
if((Acm->HeaderVersion != ACM_HEADER_VERSION_3) && (Acm->HeaderVersion != ACM_HEADER_VERSION_0)){
printf ("ACM header Version 4 or higher, bypassing other checks!\n");
return TRUE;
}
Buffer = (UINT8 *)(Acm + 1);
Buffer += Acm->KeySize * 4;
if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
} else {
Buffer += 4;
Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
}
Buffer += Acm->ScratchSize * 4;
if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) {
ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer;
if ((UINTN)ChipsetAcmInformationTable >= (UINTN)Acm + AcmMaxSize) {
printf ("ACM invalid : ChipsetAcmInformationTable!\n");
return FALSE;
}
if (CompareGuid ((EFI_GUID *)&ChipsetAcmInformationTable->Guid, (EFI_GUID *)&mChipsetAcmInformationTableGuid03) != 0) {
printf ("ACM invalid : ChipsetACMGuid!\n");
return FALSE;
}
if (ChipsetAcmInformationTable->ChipsetACMType != CHIPSET_ACM_TYPE_BIOS) {
printf ("ACM invalid : ChipsetACMType!\n");
return FALSE;
}
if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
printf ("ACM invalid : ChipsetACMVersion!\n");
return FALSE;
}
if ((UINTN)ChipsetAcmInformationTable + ChipsetAcmInformationTable->Length > (UINTN)Acm + AcmMaxSize) {
printf ("ACM invalid : ChipsetACMLength!\n");
return FALSE;
}
if (ChipsetAcmInformationTable->ChipsetIDList >= AcmMaxSize) {
printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
return FALSE;
}
ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList);
if (ChipsetIdList->Count == 0) {
printf ("ACM invalid : ChipsetACMChipsetIDListCount!\n");
return FALSE;
}
if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(CHIPSET_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_CHIPSET_ID) > AcmMaxSize) {
printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
return FALSE;
}
if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
goto End;
}
if (ChipsetAcmInformationTable->ProcessorIDList >= AcmMaxSize) {
printf ("ACM invalid : ChipsetACMProcessorIDList!\n");
return FALSE;
}
ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList);
if (ProcessorIdList->Count == 0) {
printf ("ACM invalid : ChipsetACMProcessorIdListCount!\n");
return FALSE;
}
if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(PROCESSOR_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_PROCESSOR_ID) > AcmMaxSize) {
printf ("ACM invalid : ChipsetACMProcessorIdList!\n");
return FALSE;
}
}
End:
return TRUE;
}
VOID
FillFitTable (
IN UINT8 *FvBuffer,
IN UINT32 FvSize,
IN UINT8 *FitTableOffset
)
/*++
Routine Description:
Fill the FIT table information to FvRecovery
Arguments:
FvBuffer - FvRecovery binary buffer
FvSize - FvRecovery size
FitTableOffset - The offset of FIT table in FvRecovery file
Returns:
None
--*/
{
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
UINT32 FitIndex;
UINT32 Index;
UINT8 Checksum;
UINTN SubIndex;
FIT_TABLE_CONTEXT_ENTRY TempContextEntry;
FIRMWARE_INTERFACE_TABLE_ENTRY TempTableEntry;
//
// 1. FitPointer
//
*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
if (gFitTableContext.FitTablePointerOffset2 != 0) {
*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
}
FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FitTableOffset;
FitIndex = 0;
//
// 2. FitHeader
//
FitEntry[FitIndex].Address = *(UINT64 *)"_FIT_ ";
*(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.FitEntryNumber;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.FitHeaderVersion;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_HEADER;
FitEntry[FitIndex].C_V = 1;
//
// Checksum will be updated later...
//
FitEntry[FitIndex].Checksum = 0;
//
// 3. Microcode
//
FitIndex++;
for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
FitEntry[FitIndex].Address = gFitTableContext.Microcode[Index].Address;
*(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.Microcode[Index].Size / 16;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.MicrocodeVersion;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_MICROCODE;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 4. StartupAcm
//
if (gFitTableContext.StartupAcm.Address != 0) {
FitEntry[FitIndex].Address = gFitTableContext.StartupAcm.Address;
*(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.StartupAcm.Size / 16;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.StartupAcmVersion;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_STARTUP_ACM;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 4.5. DiagnosticAcm
//
if (gFitTableContext.DiagnstAcm.Address != 0) {
FitEntry[FitIndex].Address = gFitTableContext.DiagnstAcm.Address;
*(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.DiagnstAcmVersion;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_DIAGNST_ACM;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 5. BiosModule
//
//
// BiosModule segments order needs to be put from low addresss to high for Btg requirement
//
if (gFitTableContext.BiosModuleNumber > 1) {
for (Index = 0; Index < (UINTN)gFitTableContext.BiosModuleNumber - 1; Index++){
for (SubIndex = 0; SubIndex < gFitTableContext.BiosModuleNumber - Index - 1; SubIndex++) {
if (gFitTableContext.BiosModule[SubIndex].Address > gFitTableContext.BiosModule[SubIndex + 1].Address) {
CopyMem (&TempContextEntry, &gFitTableContext.BiosModule[SubIndex], sizeof(FIT_TABLE_CONTEXT_ENTRY));
CopyMem (&gFitTableContext.BiosModule[SubIndex], &gFitTableContext.BiosModule[SubIndex + 1], sizeof(FIT_TABLE_CONTEXT_ENTRY));
CopyMem (&gFitTableContext.BiosModule[SubIndex + 1], &TempContextEntry, sizeof(FIT_TABLE_CONTEXT_ENTRY));
}
}
}
}
for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
FitEntry[FitIndex].Address = gFitTableContext.BiosModule[Index].Address;
*(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.BiosModule[Index].Size / 16;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.BiosModuleVersion;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_BIOS_MODULE;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 6. Optional module
//
for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) {
FitEntry[FitIndex].Address = gFitTableContext.OptionalModule[Index].Address;
*(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.OptionalModule[Index].Size;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.OptionalModule[Index].Version;
FitEntry[FitIndex].Type = (UINT8)gFitTableContext.OptionalModule[Index].Type;
if (FitEntry[FitIndex].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) {
FitEntry[FitIndex].Rsvd = (UINT8)gFitTableContext.OptionalModule[Index].SubType;
}
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 7. Port module
//
for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
FitEntry[FitIndex].Address = gFitTableContext.PortModule[Index].Address + ((UINT64)gFitTableContext.PortModule[Index].Size << 32);
*(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.PortModule[Index].Version;
FitEntry[FitIndex].Type = (UINT8)gFitTableContext.PortModule[Index].Type;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// The FIT records must always be arranged in the ascending order of their type attribute in the FIT.
//
for (Index = 0; Index < (UINTN)FitIndex - 1; Index++){
for (SubIndex = 0; SubIndex < FitIndex - Index - 1; SubIndex++) {
if (FitEntry[SubIndex].Type > FitEntry[SubIndex + 1].Type) {
CopyMem (&TempTableEntry, &FitEntry[SubIndex], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
CopyMem (&FitEntry[SubIndex], &FitEntry[SubIndex + 1], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
CopyMem (&FitEntry[SubIndex + 1], &TempTableEntry, sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
}
}
}
//
// Update FIT header signature as final step
//
Checksum = CalculateChecksum8 ((UINT8 *)&FitEntry[0], sizeof (FIRMWARE_INTERFACE_TABLE_ENTRY) * FitIndex);
FitEntry[0].Checksum = Checksum;
}
VOID
ClearFitTable (
IN UINT8 *FvBuffer,
IN UINT32 FvSize
)
/*++
Routine Description:
Clear the FIT table information to Fvrecovery
Arguments:
FvBuffer - Fvrecovery binary buffer
FvSize - Fvrecovery size
Returns:
None
--*/
{
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
UINT32 EntryNum;
UINT32 FitIndex;
UINT64 FitTablePointer;
UINT8 *Buffer;
UINT32 BufferSize;
FitTablePointer = *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY (FitTablePointer, FvBuffer, FvSize);
//
// Clear FIT pointer
//
*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = 0xEEEEEEEEEEEEEEEEull;
if (gFitTableContext.FitTablePointerOffset2 != 0) {
*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = 0xEEEEEEEEEEEEEEEEull;
}
//
// Clear FIT table
//
EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
for (FitIndex = 0; FitIndex < EntryNum; FitIndex++) {
switch (FitEntry[FitIndex].Type) {
case FIT_TABLE_TYPE_BIOS_POLICY:
case FIT_TABLE_TYPE_KEY_MANIFEST:
case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
case FIT_TABLE_TYPE_BIOS_DATA_AREA:
case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
//
// Clear FIT table data buffer
//
Buffer = FLASH_TO_MEMORY (FitEntry[FitIndex].Address, FvBuffer, FvSize);
BufferSize = (*(UINT32 *)FitEntry[FitIndex].Size) & 0xFFFFFF;
SetMem (Buffer, BufferSize, 0xFF);
break;
default:
break;
}
//
// Clear FIT table itself
//
SetMem (&FitEntry[FitIndex], sizeof(FitEntry[FitIndex]), 0xFF);
}
}
STATUS
WriteOutputFile (
IN CHAR8 *FileName,
IN UINT8 *FileData,
IN UINT32 FileSize
)
/*++
Routine Description:
Read input file
Arguments:
FileName - The input file name
FileData - The input file data
FileSize - The input file size
Returns:
STATUS_SUCCESS - Write file data successfully
STATUS_ERROR - The file data is not written
--*/
{
FILE *FpOut;
//
//Check the File Path
//
if (!CheckPath(FileName)) {
Error (NULL, 0, 0, "File path is invalid!", NULL);
return STATUS_ERROR;
}
//
// Open the output FvRecovery.fv file
//
if ((FpOut = fopen (FileName, "w+b")) == NULL) {
Error (NULL, 0, 0, "Unable to open file", "%s", FileName);
return STATUS_ERROR;
}
//
// Write the output FvRecovery.fv file
//
if ((fwrite (FileData, 1, FileSize, FpOut)) != FileSize) {
Error (NULL, 0, 0, "Write output file error!", NULL);
fclose (FpOut);
return STATUS_ERROR;
}
//
// Close the output FvRecovery.fv file
//
fclose (FpOut);
return STATUS_SUCCESS;
}
UINT32
GetFvRecoveryInfoFromFd (
IN UINT8 *FdBuffer,
IN UINT32 FdFileSize,
OUT UINT8 **FvRecovery
)
/*++
Routine Description:
Get FvRecovery information from Fd file.
Arguments:
FdBuffer - Fd file buffer.
FdFileSize - Fd file size.
FvRecovery - FvRecovery pointer in Fd file buffer
Returns:
FvRecovery file size
--*/
{
UINT8 *FileBuffer = NULL;
UINT32 FvRecoveryFileSize =0;
EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
UINT32 FvLength;
UINT32 FileLength;
*FvRecovery = NULL;
FileBuffer = FindNextFvHeader (FdBuffer, FdFileSize);
if (FileBuffer == NULL) {
return 0;
}
while ((UINTN)FileBuffer < (UINTN)FdBuffer + FdFileSize) {
FvLength = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->FvLength;
if (FindFileFromFvByGuid (FileBuffer, FvLength, &VTFGuid, &FileLength) != NULL) {
//
// Found the VTF
//
FvRecoveryFileSize = FvLength;
*FvRecovery = FileBuffer;
}
//
// Next fv
//
FileBuffer = (UINT8 *)FileBuffer + FvLength;
if ((UINTN)FileBuffer >= (UINTN)FdBuffer + FdFileSize) {
break;
}
FileBuffer = FindNextFvHeader (FileBuffer, (UINTN)FdBuffer + FdFileSize - (UINTN)FileBuffer);
if (FileBuffer == NULL) {
break;
}
}
//
// Return
//
return FvRecoveryFileSize;
}
UINT32
GetFitEntryInfo (
IN UINT8 *FvBuffer,
IN UINT32 FvSize
)
/*++
Routine Description:
Fill the FIT table information to Fvrecovery
Arguments:
FvBuffer - Fvrecovery binary buffer
FvSize - Fvrecovery size
Returns:
0 - Fit Table not found
--*/
{
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
UINT32 FitIndex;
UINT32 FitTableOffset;
//
// 1. FitPointer
//
if (gFitTableContext.FitTablePointerOffset == 0) {
gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
}
gFitTableContext.FitTablePointerOffset2 = 0;
FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
FitIndex = 0;
//
// 2. FitHeader
//
if (FitEntry[FitIndex].Address != *(UINT64 *)"_FIT_ ") {
return 0;
}
if (FitEntry[FitIndex].Type != FIT_TABLE_TYPE_HEADER) {
return 0;
}
gFitTableContext.FitEntryNumber = *(UINT32 *)&FitEntry[FitIndex].Size[0];
gFitTableContext.FitHeaderVersion = FitEntry[FitIndex].Version;
//
// 3. FitEntry
//
FitIndex++;
for (; FitIndex < gFitTableContext.FitEntryNumber; FitIndex++) {
switch (FitEntry[FitIndex].Type) {
case FIT_TABLE_TYPE_MICROCODE:
gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.MicrocodeVersion = FitEntry[FitIndex].Version;
gFitTableContext.MicrocodeNumber ++;
break;
case FIT_TABLE_TYPE_STARTUP_ACM:
gFitTableContext.StartupAcm.Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.StartupAcmVersion = FitEntry[FitIndex].Version;
break;
case FIT_TABLE_TYPE_BIOS_MODULE:
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = *(UINT32 *)&FitEntry[FitIndex].Size[0] * 16;
gFitTableContext.BiosModuleVersion = FitEntry[FitIndex].Version;
gFitTableContext.BiosModuleNumber ++;
break;
case FIT_TABLE_TYPE_TPM_POLICY:
case FIT_TABLE_TYPE_TXT_POLICY:
if (FitEntry[FitIndex].Version == 0) {
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT32)(FitEntry[FitIndex].Address >> 32);
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = FitEntry[FitIndex].Version;
gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = FitEntry[FitIndex].Type;
gFitTableContext.PortModuleNumber ++;
break;
}
// Not Port Configure, pass through
default: // Others
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = *(UINT32 *)&FitEntry[FitIndex].Size[0];
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = FitEntry[FitIndex].Version;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = FitEntry[FitIndex].Type;
gFitTableContext.OptionalModuleNumber ++;
break;
}
}
return gFitTableContext.FitEntryNumber;
}
STATUS
FitGen (
IN INTN argc,
IN CHAR8 **argv
)
/*++
Routine Description:
Main function for FitGen.
Arguments:
argc - Number of command line parameters.
argv - Array of pointers to parameter strings.
Returns:
STATUS_SUCCESS - Utility exits successfully.
STATUS_ERROR - Some error occurred during execution.
--*/
{
UINT32 FvRecoveryFileSize;
UINT8 *FileBuffer;
UINT8 *FileBufferRaw;
UINTN FitEntryNumber;
UINT8 *FitTableOffset;
STATUS Status;
UINT32 FitTableSize;
BOOLEAN IsFv;
UINT8 *FdFileBuffer;
UINT32 FdFileSize;
UINT8 *AcmBuffer;
FileBufferRaw = NULL;
//
// Step 0: Check FV or FD
//
if (((strcmp (argv[1], "-D") == 0) ||
(strcmp (argv[1], "-d") == 0)) ) {
IsFv = FALSE;
} else {
IsFv = TRUE;
}
//
// Step 1: Read InputFvRecovery.fv data
//
if (IsFv) {
Status = ReadInputFile (argv[1], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", "%s", argv[1]);
goto exitFunc;
}
FdFileBuffer = FileBuffer;
FdFileSize = FvRecoveryFileSize;
} else {
Status = ReadInputFile (argv[2], &FdFileBuffer, &FdFileSize, &FileBufferRaw);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
goto exitFunc;
}
//
// Get Fvrecovery information
//
FvRecoveryFileSize = GetFvRecoveryInfoFromFd (FdFileBuffer, FdFileSize, &FileBuffer);
if ((FvRecoveryFileSize == 0) || (FileBuffer == NULL)) {
Error (NULL, 0, 0, "FvRecovery not found in Fd file!", NULL);
Status = STATUS_ERROR;
goto exitFunc;
}
}
//
// Step 2: Calculate FIT entry number.
//
FitEntryNumber = GetFitEntryNumber (argc, argv, FdFileBuffer, FdFileSize);
if (!gFitTableContext.Clear) {
if (FitEntryNumber == 0) {
Status = STATUS_ERROR;
goto exitFunc;
}
//
// For debug
//
PrintFitData ();
//
// Add 1 more FitEntry as place holder, because we need exclude FIT table itself
//
FitEntryNumber++;
//
// Step 3: Get enough space in FvRecovery.fv
//
FitTableOffset = GetFreeSpaceFromFv (FileBuffer, FvRecoveryFileSize, FitEntryNumber);
if (FitTableOffset == NULL) {
return STATUS_ERROR;
}
FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
FitTableSize += FIT_ALIGNMENT;
FitTableSize &= ~FIT_ALIGNMENT;
CheckOverlap (
MEMORY_TO_FLASH (FitTableOffset, FdFileBuffer, FdFileSize),
FitTableSize
);
//
// Get ACM buffer
//
if (gFitTableContext.StartupAcm.Address != 0) {
AcmBuffer = FLASH_TO_MEMORY(gFitTableContext.StartupAcm.Address, FdFileBuffer, FdFileSize);
if ((AcmBuffer < FdFileBuffer) || (AcmBuffer + gFitTableContext.StartupAcm.Size > FdFileBuffer + FdFileSize)) {
printf ("ACM out of range - can not validate it\n");
AcmBuffer = NULL;
}
if (AcmBuffer != NULL) {
if (CheckAcm ((ACM_FORMAT *)AcmBuffer, gFitTableContext.StartupAcm.Size)) {
DumpAcm ((ACM_FORMAT *)AcmBuffer);
} else {
Status = STATUS_ERROR;
goto exitFunc;
}
}
}
//
// Step 4: Fill the FIT table one by one
//
FillFitTable (FdFileBuffer, FdFileSize, FitTableOffset);
//
// For debug
//
PrintFitTable (FdFileBuffer, FdFileSize);
} else {
printf ("Clear FIT table ...\n");
//
// Step 3: Get FIT table info
//
FitEntryNumber = GetFitEntryInfo (FdFileBuffer, FdFileSize);
if (FitEntryNumber == 0) {
Error (NULL, 0, 0, "No FIT table found", NULL);
return STATUS_ERROR;
}
//
// For debug
//
PrintFitTable (FdFileBuffer, FdFileSize);
//
// Step 4: Clear FIT table
//
ClearFitTable (FdFileBuffer, FdFileSize);
printf ("Clear FIT table Done!\n");
}
//
// Step 5: Write OutputFvRecovery.fv data
//
if (IsFv) {
Status = WriteOutputFile (argv[2], FileBuffer, FvRecoveryFileSize);
} else {
Status = WriteOutputFile (argv[3], FdFileBuffer, FdFileSize);
}
exitFunc:
if (FileBufferRaw != NULL) {
free ((VOID *)FileBufferRaw);
}
return Status;
}
STATUS
FitView (
IN INTN argc,
IN CHAR8 **argv
)
/*++
Routine Description:
View function for FitGen.
Arguments:
argc - Number of command line parameters.
argv - Array of pointers to parameter strings.
Returns:
STATUS_SUCCESS - Utility exits successfully.
STATUS_ERROR - Some error occurred during execution.
--*/
{
UINT32 FvRecoveryFileSize;
UINT8 *FileBuffer;
UINT8 *FileBufferRaw = NULL;
STATUS Status;
//
// Step 1: Read input file
//
Status = ReadInputFile (argv[2], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
goto exitFunc;
}
// no -f option, use default FIT pointer offset
if (argc == 3) {
//
// Use default address
//
gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
} else if (stricmp (argv[3], "-f") == 0) {
if (argc == 5) {
//
// Get offset from parameter
//
gFitTableContext.FitTablePointerOffset = xtoi (argv[3 + 1]);
} else {
Error (NULL, 0, 0, "FIT offset not specified!", NULL);
goto exitFunc;
}
} else {
Error (NULL, 0, 0, "Invalid view option: ", "%s", argv[3]);
goto exitFunc;
}
//
// For debug
//
PrintFitTable (FileBuffer, FvRecoveryFileSize);
exitFunc:
if (FileBufferRaw != NULL) {
free ((VOID *)FileBufferRaw);
}
return Status;
}
int
main (
int argc,
char **argv
)
/*++
Routine Description:
Main function.
Arguments:
argc - Number of command line parameters.
argv - Array of pointers to parameter strings.
Returns:
STATUS_SUCCESS - Utility exits successfully.
STATUS_ERROR - Some error occurred during execution.
--*/
{
SetUtilityName (UTILITY_NAME);
//
// Display utility information
//
PrintUtilityInfo ();
//
// Verify the correct number of arguments
//
if (argc >= MIN_VIEW_ARGS && stricmp (argv[1], "-view") == 0) {
return FitView (argc, argv);
} else if (argc >= MIN_ARGS) {
return FitGen (argc, argv);
} else {
Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);
PrintUsage ();
return STATUS_ERROR;
}
}
unsigned int
xtoi (
char *str
)
/*++
Routine Description:
Convert hex string to uint
Arguments:
str - The string
Returns:
--*/
{
unsigned int u;
char c;
unsigned int m;
if (str == NULL) {
return 0;
}
m = (unsigned int) -1 >> 4;
//
// skip preceeding white space
//
while (*str && *str == ' ') {
str += 1;
}
//
// skip preceeding zeros
//
while (*str && *str == '0') {
str += 1;
}
//
// skip preceeding x/X character
//
if (*str && (*str == 'x' || *str == 'X')) {
str += 1;
}
//
// convert hex digits
//
u = 0;
c = *(str++);
while (c) {
if (c >= 'a' && c <= 'f') {
c -= 'a' - 'A';
}
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
if (u > m) {
return (unsigned int) -1;
}
u = (u << 4) | (c - (c >= 'A' ? 'A' - 10 : '0'));
} else {
//
// Let application exit immediately
//
Error (NULL, 0, 0, "Hex value is expected!", NULL);
exit (0);
break;
}
c = *(str++);
}
return u;
}