/**@file
This utility is part of build process for IA32/X64 FD.
It generates FIT table.
Copyright (c) 2010-2022, 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 MICROCODE_EXTERNAL_HEADER_SIZE 0x30
#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE 256
#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE 384
#define ACM_XMSS_PUBLIC_KEY_SIZE 64
#define ACM_XMSS_SIGNATURE_SIZE 2692
#define ACM_HEADER_VERSION_5 0x50004
#define ACM_HEADER_VERSION_4 (4 << 16)
#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
#define NIBBLES_TO_BYTE(A, B) (UINT8)(((A & (0x0F)) << 4) | (B & 0x0F))
//
//Flash Map 0 Register (Flash Descriptor Records)
//
typedef struct {
UINT32 Fcba : 8; //Bits[7:0]: Flash Component Base Address
UINT32 Nc : 2; //Bits[9:8]: Number of Components
UINT32 Rsvd0: 1; //Bit10: Reserved
UINT32 Rsvd1: 1; //Bit11: Reserved
UINT32 Rsvd2: 1; //Bit12: Reserved
UINT32 Rsvd3: 3; //Bits[15:13]: Reserved
UINT32 Frba : 8; //Bits[23:16]: Flash Region Base Address
UINT32 Rsvd4: 3; //Bits[26:24]: Reserved
UINT32 Rsvd5: 5; //Bits[31:27]: Reserved
} FLASH_MAP_0_REGISTER;
//
//Flash Region 1 (BIOS) Register (Flash Descriptor Records)
//
typedef struct {
UINT32 RegionBase : 15; //Bits[14:0]: Region base
UINT32 Rsvd : 1; //Bit15: Reserved
UINT32 RegionLimit: 15; //Bits[30:16]: Region limit
UINT32 Rsvd1 : 1; //Bit31: Reserved
} FLASH_REGION_1_BIOS_REGISTER;
#define FLASH_VALID_SIGNATURE 0x0FF0A55A //Flash Valid Signature (Flash Descriptor Records)
#define FLVALSIG_BASE_OFFSET 0x10 //Flash Valid Signature Base Offset
#define FLMAP0_BASE_OFFSET 0x14 //Flash Map 0 Register Base Offset
#define ACMFV_GUID \
{ 0x8a4b197f, 0x1113, 0x43d0, { 0xa2, 0x3f, 0x26, 0xf3, 0x69, 0xb2, 0xb8, 0x41 }}
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
#define DEFAULT_ACM_EXTENDED_MASK 0x00FFFFFF
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;
typedef union {
struct {
UINT32 Stepping : 4;
UINT32 Model : 4;
UINT32 Family : 4;
UINT32 Type : 2;
UINT32 Reserved1 : 2;
UINT32 ExtendedModel : 4;
UINT32 ExtendedFamily: 8;
UINT32 Reserved2 : 4;
} Bits;
UINT32 Uint32;
} PROCESSOR_ID;
#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_STARTUP_ACM_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 STARTUP_ACM_FIT_ENTRY_200_VERSION 0x0200
#define MAX_MMCFW_MODULE_ENTRY 0x02
#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_PROT_BOOT_POLICY 4
#define FIT_TABLE_TYPE_MMC_FW 5
#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_FSP_BOOT_MANIFEST 13
#define FIT_TABLE_TYPE_CSE_SECURE_BOOT 16
#define FIT_TABLE_SUBTYPE_FIT_PATCH_MANIFEST 12
#define FIT_TABLE_SUBTYPE_ACM_MANIFEST 13
#define FIT_TABLE_TYPE_VAB_PROVISION_TABLE 26
#define FIT_TABLE_TYPE_VAB_BOOT_IMAGE_MANIFEST 27
#define FIT_TABLE_TYPE_VAB_BOOT_KEY_MANIFEST 28
//
// 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
UINT32 FMS; // Used by Entry Type 02 (ACM) Ver. 0x200 only
UINT32 FMSMask; // Used by Entry Type 02 (ACM) Ver. 0x200 only
} FIT_TABLE_CONTEXT_ENTRY;
typedef struct {
BOOLEAN Clear;
UINT32 FitTablePointerOffset;
UINT32 FitTablePointerOffset2;
UINT32 FitEntryNumber;
UINT32 BiosModuleNumber;
UINT32 MicrocodeNumber;
UINT32 MmcFwNumber;
UINT32 StartupAcmNumber;
UINT32 OptionalModuleNumber;
UINT32 PortModuleNumber;
UINT32 GlobalVersion;
UINT32 FitHeaderVersion;
FIT_TABLE_CONTEXT_ENTRY StartupAcm[MAX_STARTUP_ACM_ENTRY];
UINT32 StartupAcmFvSize;
FIT_TABLE_CONTEXT_ENTRY DiagnstAcm;
UINT32 DiagnstAcmVersion;
FIT_TABLE_CONTEXT_ENTRY ProtBootPolicy;
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];
FIT_TABLE_CONTEXT_ENTRY MmcFw[MAX_MMCFW_MODULE_ENTRY];
UINT64 TopFlashAddressRemapValue;
} FIT_TABLE_CONTEXT;
FIT_TABLE_CONTEXT gFitTableContext = {0};
unsigned int
xtoi (
char *str
);
/**
Pass in supported CPU extended family/extended model/type
/family/model without stepping or CPU FMS >> 4.
@param FitEntry Pointer to Fit Entry table.
@param AcmFamilyModel Acm Family Model stepping.
@param AcmMask ACM mask.
@return STATUS_SUCCESS The file found and data read.
**/
STATUS
SetFirmwareInterfaceTableEntryAcmFms(
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry,
UINT32 AcmFamilyModel,
UINT32 AcmMask
)
{
if (FitEntry == NULL) {
return STATUS_ERROR;
}
FitEntry->Checksum = (UINT8)(((AcmFamilyModel & 0x000F0000) >> 16) | (((AcmMask & 0x000F0000) >> 16) << 4));
FitEntry->Rsvd = (UINT8)((AcmMask & 0x0000FF00) >> 8);
FitEntry->Size[2] = (UINT8)(AcmMask & 0x000000FF);
FitEntry->Size[1] = (UINT8)((AcmFamilyModel & 0x0000FF00) >> 8);
FitEntry->Size[0] = (UINT8)(AcmFamilyModel & 0x000000FF);
return STATUS_SUCCESS;
}
/**
Set the FIT Entry Size.
@param FitEntry Pointer to Fit Entry table.
@param SizeEntry Size of FIT entry.
@return STATUS_SUCCESS The file found and data read.
**/
STATUS
SetFirmwareInterfaceTableEntrySize (
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry,
UINT32 SizeEntry
)
{
if (FitEntry == NULL) {
return STATUS_ERROR;
}
FitEntry->Size[2] = (UINT8)((SizeEntry & 0x00FF0000) >> 16);
FitEntry->Size[1] = (UINT8)((SizeEntry & 0x0000FF00) >> 8);
FitEntry->Size[0] = (UINT8)(SizeEntry & 0x000000FF);
return STATUS_SUCCESS;
}
/**
Get the FIT Entry Size.
@param FitEntry Pointer to Fit Entry table.
@return FitEntry pointer
**/
UINT32
GetFirmwareInterfaceTableEntrySize (
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry
)
{
if (FitEntry == NULL) {
return 0;
}
return (((UINT32)FitEntry->Size[2] << 16) | ((UINT32)FitEntry->Size[1] << 8) | (UINT32)FitEntry->Size[0]);
}
/**
Displays the FIT utility info
@param None
@return None
**/
VOID
PrintUtilityInfo (
VOID
)
{
printf (
"%s - Tiano IA32/X64 FIT table generation Utility for FIT spec revision %i.%i."" Version %i.%i\n\n",
UTILITY_NAME,
FIT_SPEC_VERSION_MAJOR,
FIT_SPEC_VERSION_MINOR,
UTILITY_MAJOR_VERSION,
UTILITY_MINOR_VERSION
);
}
/**
Displays the utility usage syntax to STDOUT.
@param None
@return None
**/
VOID
PrintUsage (
VOID
)
{
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 |] [-I ] [-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"
"\t[-BP [-V ]\n"
"\t[-T ]\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 - The maximum size value that could place the StartupAcm in.\n");
printf ("\tStartupAcmGuid - Guid of StartupAcm Module, if StartupAcm is in a BiosModule, it will be excluded form that.\n");
printf ("\tStartupAcmFMS - Value of PROCESSOR ID (Family/Model/Stepping value called \"FMS\") - see detail on FIT spec (1.3).\n");
printf ("\tStartupAcmFMSMask - Value use for uCode (if it recognizes 0x200 Type2 entry) to do bitmask logic operation with CPU processor ID.\n");
printf ("\t If the result match to StartupAcmFMS, corresponding ACM will be loaded - see detail on FIT spec (1.3).\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 ("\tBootPolicySize - FIT entry size for type 04 boot policy.\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 ("\tBootPolicyVersion - The version for BootPolicy. (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 ("\tFixedFitLocation - Fixed FIT location in flash address. FIT table will be generated at this location and Option Modules will be directly put right before it.\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);
}
/**
Set Value of memory.
@param Buffer The pointer where we need to set the memory.
@param Length Size of memory to be set.
@param Value Value of memory to be set.
@return Buffer The pointer address.
**/
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;
}
/**
check the input Path.
@param String Passed input path.
@return TRUE If the input path is correct.
@return FLASE if the input path is not correct.
**/
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;
}
/**
Get fixed FIT location from argument.
@param argc Number of command line parameters.
@param argv Array of pointers to parameter strings.
@return FitLocation The FIT location specified by Argument.
@return 0 Argument parse fail.
**/
UINT32
GetFixedFitLocation (
IN INTN argc,
IN CHAR8 **argv
)
{
UINT32 FitLocation;
INTN Index;
FitLocation = 0;
for (Index = 0; Index + 1 < argc; Index ++) {
if ((strcmp (argv[Index], "-T") == 0) ||
(strcmp (argv[Index], "-t") == 0) ) {
FitLocation = xtoi (argv[Index + 1]);
break;
}
}
return FitLocation;
}
/**
Read input file.
@param FileName The input file name.
@param FileData The input file data, the memory is aligned.
@param FileSize The input file size.
@param FileBufferRaw The memory to hold input file data. The caller must free the memory.
@return STATUS_SUCCESS The file found and data read.
@return STATUS_ERROR The file data is not read.
@return STATUS_WARNING The file is not found.
**/
STATUS
ReadInputFile (
IN CHAR8 *FileName,
OUT UINT8 **FileData,
OUT UINT32 *FileSize,
OUT UINT8 **FileBufferRaw OPTIONAL
)
{
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;
}
/**
Find next FvHeader in the FileBuffer.
@param FileBuffer The start FileBuffer which needs to be searched.
@param FileLength The whole File Length.
@return FvHeader The FvHeader is found successfully.
@return NULL The FvHeader is not found.
**/
UINT8 *
FindNextFvHeader (
IN UINT8 *FileBuffer,
IN UINTN FileLength
)
{
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;
}
/**
Find File with GUID in an FV.
@param FvBuffer FV binary buffer.
@param FvSize FV size.
@param Guid File GUID value to be searched.
@param FileSize Guid File size.
@return FileLocation Guid File location.
@return NULL Guid File is not found.
**/
UINT8 *
FindFileFromFvByGuid (
IN UINT8 *FvBuffer,
IN UINT32 FvSize,
IN EFI_GUID *Guid,
OUT UINT32 *FileSize
)
{
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;
}
/**
Check whether a string is a GUID.
@param StringData The String.
@param Guid Guid to hold the value
@return TRUE StringData is a GUID, and Guid field is filled.
@return FALSE StringData is not a GUID.
**/
BOOLEAN
IsGuidData (
IN CHAR8 *StringData,
OUT EFI_GUID *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;
}
/**
Get FIT entry number and fill global FIT table context, from argument.
@param argc Number of command line parameters.
@param argv Array of pointers to parameter strings.
@param FdBuffer FD binary buffer.
@param FdSize FD size.
@return FitEntryNumber The FIT entry number.
@return 0 Argument parse fail.
**/
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;
}
}
}
/**
Get FIT entry number and fill global FIT table context, from argument.
@param argc Number of command line parameters.
@param argv Array of pointers to parameter strings.
@param FdBuffer FD binary buffer.
@param FdSize FD size.
@return FitEntryNumber The FIT entry number.
@return 0 Argument parse fail.
**/
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;
}
/**
Get FIT entry number and fill global FIT table context, from argument.
@param argc Number of command line parameters.
@param argv Array of pointers to parameter strings.
@param FdBuffer FD binary buffer.
@param FdSize FD size.
@return FitEntryNumber The FIT entry number.
@return 0 Argument parse fail.
**/
UINT32
GetFitEntryNumber (
IN INTN argc,
IN CHAR8 **argv,
IN UINT8 *FdBuffer,
IN UINT32 FdSize
)
{
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;
UINT32 MMCRegionOffset;
UINT8 *MMCBuffer;
UINT8 *MMCFileBuffer;
EFI_FIRMWARE_VOLUME_HEADER *MMCFvHeader;
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.StartupAcmNumber >= MAX_STARTUP_ACM_ENTRY) {
Error (NULL, 0, 0, "-I Parameter incorrect, too many StartupAcm!", NULL);
return 0;
}
//
// NOTE: BIOS INFO structure only support the default FIT entry format.
//
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Type = FIT_TABLE_TYPE_STARTUP_ACM;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Version = BiosInfoStruct[BiosInfoIndex].Version;
gFitTableContext.StartupAcmNumber ++;
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_PROT_BOOT_POLICY:
gFitTableContext.ProtBootPolicy.Type = FIT_TABLE_TYPE_PROT_BOOT_POLICY;
gFitTableContext.ProtBootPolicy.Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
gFitTableContext.ProtBootPolicy.Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
gFitTableContext.ProtBootPolicy.Version = DEFAULT_FIT_ENTRY_VERSION;
gFitTableContext.FitEntryNumber ++;
break;
case FIT_TABLE_TYPE_MMC_FW:
if (gFitTableContext.MmcFwNumber >= MAX_MMCFW_MODULE_ENTRY) {
Error (NULL, 0, 0, "-I Parameter incorrect, Too many Bios Mmc Fw!", NULL);
return 0;
}
MMCRegionOffset = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
if (MMCRegionOffset == 0) {
continue;
}
MMCBuffer = FLASH_TO_MEMORY (MMCRegionOffset, FdBuffer, FdSize);
MMCFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MMCBuffer;
if (MMCFvHeader->Signature == EFI_FVH_SIGNATURE) {
MMCFileBuffer = GetMicrocodeBufferFromFv (MMCFvHeader);
} else {
MMCFileBuffer = MMCBuffer;
}
gFitTableContext.MmcFw[gFitTableContext.MmcFwNumber].Type = BiosInfoStruct[BiosInfoIndex].Type;
gFitTableContext.MmcFw[gFitTableContext.MmcFwNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address + (UINT32)((UINTN) MMCFileBuffer - (UINTN) MMCBuffer);
gFitTableContext.MmcFw[gFitTableContext.MmcFwNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
gFitTableContext.MmcFw[gFitTableContext.MmcFwNumber].Version = DEFAULT_FIT_ENTRY_VERSION;
gFitTableContext.MmcFwNumber++;
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_FSP_BOOT_MANIFEST:
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
//
while (TRUE) {
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-S") != 0) &&
(strcmp (argv[Index], "-s") != 0)) ) {
if (gFitTableContext.StartupAcmNumber == 0) {
printf ("-S not found. WARNING!\n");
}
// Error (NULL, 0, 0, "-S Parameter incorrect, expect -S!", NULL);
// return 0;
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;
}
gFitTableContext.StartupAcmFvSize = FdSize;
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.StartupAcmNumber >= MAX_STARTUP_ACM_ENTRY) {
Error (NULL, 0, 0, "-S Parameter incorrect, too many StartupAcm!", NULL);
return 0;
}
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Type = FIT_TABLE_TYPE_STARTUP_ACM;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Size = FileSize;
//
// 1.1 Support 0x200 StartupAcm Information
// With the -I parameter should assign the type 2 entry with 0x200 version format
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-I") != 0) &&
(strcmp (argv[Index], "-i") != 0)) ) {
//
// Bypass
//
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Version = gFitTableContext.GlobalVersion;
} else {
if (Index + 2 >= argc) {
//
// Should get two input value, but not sufficient
//
Error (NULL, 0, 0, "-I Parameter incorrect, Require two inputs value!", NULL);
return 0;
} else {
//
// With the -I parameter should assign the type 2 entry version as 0x200 format
//
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Version = STARTUP_ACM_FIT_ENTRY_200_VERSION;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].FMS = (UINT32)xtoi (argv[Index + 1]);
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].FMSMask = (UINT32)xtoi (argv[Index + 2]);
Index += 3;
}
}
//
// 1.2 StartupAcm version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
} else {
//
// Get offset from parameter
//
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Version = gFitTableContext.GlobalVersion;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Version = xtoi (argv[Index + 1]);
Index += 2;
}
gFitTableContext.StartupAcmNumber ++;
gFitTableContext.FitEntryNumber ++;
};
//
// 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;
}
//
// 1.1 Support 0x200 DiagnosticAcm Information
// With the -I parameter should assign the Type 2 entry with 0x200 version format
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-I") != 0) &&
(strcmp (argv[Index], "-i") != 0)) ) {
//
// Bypass
//
printf("SET DIAG ACM version 0x100\n");
gFitTableContext.DiagnstAcmVersion = DEFAULT_FIT_ENTRY_VERSION;
} else {
printf("SET DIAG FUSA ACM version 0x200\n");
gFitTableContext.DiagnstAcmVersion = STARTUP_ACM_FIT_ENTRY_200_VERSION;
gFitTableContext.DiagnstAcm.FMS = (UINT32)xtoi (argv[Index + 1]);
gFitTableContext.DiagnstAcm.FMSMask = (UINT32)xtoi (argv[Index + 2]);
Index += 3;
}
gFitTableContext.DiagnstAcm.Type = FIT_TABLE_TYPE_DIAGNST_ACM;
gFitTableContext.DiagnstAcm.Address = (UINT32) (UINTN) FileBuffer;
gFitTableContext.DiagnstAcm.Size = 0;
gFitTableContext.FitEntryNumber ++;
} 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++;
}
//
// 6th, try FIT boot policy data
//
if ((Index < argc) &&
((strcmp(argv[Index], "-BP") == 0) ||
(strcmp(argv[Index], "-bp") == 0))) {
if (Index + 1 >= argc) {
Error(NULL, 0, 0, "-BP: Invalid Parameters.", NULL);
FitEntryNumber = 0;
}
gFitTableContext.StartupAcmFvSize = GetFvAcmSizeFromFd(FdBuffer, FdSize);
if (gFitTableContext.StartupAcmFvSize == 0) {
Error(NULL, 0, 0, "FV_ACM not found in Fd file!", NULL);
}
//
// FIT type 04 record shares FV allocated space with FV_ACM.
//
FileSize = xtoi(argv[Index + 1]);
if (gFitTableContext.StartupAcm[0].Size + FileSize > gFitTableContext.StartupAcmFvSize) {
Error(NULL, 0, 0, "Error: not enough FV_ACM room for FIT type 04 record!", NULL);
FitEntryNumber = 0;
}
FileBuffer = malloc(FileSize);
if (FileBuffer == NULL) {
Error(NULL, 0, 0, "No sufficient memory to allocate!", NULL);
FitEntryNumber = 0;
}
SetMem(FileBuffer, FileSize, 0xFF);
gFitTableContext.ProtBootPolicy.Type = FIT_TABLE_TYPE_PROT_BOOT_POLICY;
gFitTableContext.ProtBootPolicy.Address = gFitTableContext.StartupAcm[0].Address + gFitTableContext.StartupAcm[0].Size;
gFitTableContext.ProtBootPolicy.Size = FileSize;
gFitTableContext.ProtBootPolicy.Version = 0;
Index += 2;
//
// 6.1 PROT Module version
//
if ((Index + 1 >= argc) ||
((strcmp (argv[Index], "-V") != 0) &&
(strcmp (argv[Index], "-v") != 0)) ) {
//
// Bypass
//
gFitTableContext.ProtBootPolicy.Version = gFitTableContext.GlobalVersion;
} else {
//
// Get offset from parameter
//
gFitTableContext.ProtBootPolicy.Version = xtoi(argv[Index + 1]);
Index += 2;
}
gFitTableContext.FitEntryNumber++;
}
//
// Final: Check StartupAcm in BiosModule.
//
for (Index = 0; Index < (INTN)gFitTableContext.StartupAcmNumber; Index++) {
CheckOverlap (gFitTableContext.StartupAcm[Index].Address, gFitTableContext.StartupAcm[Index].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_FSP_BOOT_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_PROVISION_TABLE) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_IMAGE_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_KEY_MANIFEST)) {
// NOTE: It might be virtual address now. Just put a place holder.
FitEntryNumber ++;
}
}
return FitEntryNumber;
}
/**
No enough space - it might happen that it is occupied by AP wake vector.
Last chance - skip this and search again.
@param FvBuffer FvRecovery binary buffer.
@param Address Address to be searched from.
@param Size Size need to be filled.
@return FitTableOffset The FIT table offset.
@return NULL No enough space for FIT table.
**/
VOID *
FindSpaceSkipApVector (
IN UINT8 *FvBuffer,
IN UINT8 *Address,
IN UINTN Size
)
{
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;
}
/**
Get free space for FIT table from FvRecovery.
@param FvBuffer FvRecovery binary buffer.
@param FvSize FvRecovery size.
@param FitTableSize The FIT table size.
@param FixedFitLocation Fixed FIT location provided by argument.
@return FitTableOffset The offset of FIT table in FvRecovery file.
@return NULL Free space not found.
**/
VOID *
GetFreeSpaceForFit (
IN UINT8 *FvBuffer,
IN UINT32 FvSize,
IN UINT32 FitTableSize,
IN UINT32 FixedFitLocation
)
{
UINT8 *FitTableOffset;
INTN Index;
INTN SubIndex;
UINT8 *OptionalModuleAddress;
EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
UINT32 AlignedSize;
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;
}
}
if (FixedFitLocation != 0) {
//
// Get Free space from fixed location
//
FitTableOffset = (UINT8 *) FLASH_TO_MEMORY (FixedFitLocation, FvBuffer, FvSize);
} else {
//
// Get Free Space from FvRecovery
//
FitTableOffset = NULL;
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvBuffer;
FvLength = FvHeader->FvLength;
FileHeader = (EFI_FFS_FILE_HEADER *)(FvBuffer + FvHeader->HeaderLength);
Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
//
// Get EFI_FFS_VOLUME_TOP_FILE_GUID location
//
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;
}
FitTableOffset = (UINT8 *)((UINTN)FitTableOffset & ~FIT_ALIGNMENT);
FitTableOffset = (UINT8 *)(FitTableOffset - FitTableSize);
}
//
// Check the target space for FIT table
//
// 1. If FIT table has a fixed location, we assume users can provide an empty space for FIT table
// and Option Modules.
// 2. If FIT table location is dynamicly calculated in FvRecovery, we give a last chance to skip
// space for AP Vector.
//
for (Index = 0; Index < (INTN)(FitTableSize); Index ++) {
if (FitTableOffset[Index] != 0xFF) {
if (FixedFitLocation != 0) {
Error (NULL, 0, 0, "Reserved space for FIT table is not empty!", NULL);
return NULL;
}
//
// 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_FSP_BOOT_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_PROVISION_TABLE) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_IMAGE_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_KEY_MANIFEST)) {
// 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_FSP_BOOT_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_PROVISION_TABLE) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_IMAGE_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_KEY_MANIFEST)) {
// Let it 64 byte align
OptionalModuleAddress = (UINT8 *)((UINTN)OptionalModuleAddress & ~BIOS_MODULE_ALIGNMENT);
}
for (SubIndex = 0; SubIndex < (INTN)(AlignedSize); SubIndex ++) {
if (OptionalModuleAddress[SubIndex] != 0xFF) {
if (FixedFitLocation != 0) {
Error (NULL, 0, 0, "No enough space for Option Modules!", NULL);
return NULL;
}
//
// 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_FSP_BOOT_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_PROVISION_TABLE) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_IMAGE_MANIFEST) ||
(gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_VAB_BOOT_KEY_MANIFEST)) {
CheckOverlap (gFitTableContext.OptionalModule[Index].Address, AlignedSize);
}
}
return FitTableOffset;
}
/**
Output FIT table information.
@param None
@return None
**/
VOID
PrintFitData (
VOID
)
{
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);
for (Index = 0; Index < gFitTableContext.StartupAcmNumber; Index++) {
printf("StartupAcm[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.StartupAcm[Index].Address, gFitTableContext.StartupAcm[Index].Size, gFitTableContext.StartupAcm[Index].Version);
}
if (gFitTableContext.DiagnstAcm.Address != 0) {
printf ("DiagnosticAcm - (0x%08x, 0x%08x, 0x%04x)\n", gFitTableContext.DiagnstAcm.Address, gFitTableContext.DiagnstAcm.Size, gFitTableContext.DiagnstAcmVersion);
}
if (gFitTableContext.ProtBootPolicy.Address != 0) {
printf ("ProtBootPolicy - (0x%08x, 0x%08x, 0x%04x)\n", gFitTableContext.ProtBootPolicy.Address, gFitTableContext.ProtBootPolicy.Size, gFitTableContext.ProtBootPolicy.Version);
}
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.MmcFwNumber; Index++) {
printf ("MmcFw[%d] - (0x%08x, 0x%08x)\n", Index, gFitTableContext.MmcFw[Index].Address, gFitTableContext.MmcFw[Index].Size);
}
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",
"BOOT_POLICY",
"MMCFW ",
" ",
"BIOS_MODULE",
"TPM_POLICY ",
"BIOS_POLICY",
"TXT_POLICY ",
"KEYMANIFEST",
"BP_MANIFEST",
"FSP_BOOT_MF",
" ",
" ",
"CSE_SECUREB"
};
/**
Convert FitEntry type to a string.
@param FitEntry Fit entry
@return String
**/
CHAR8 mFitSignature[] = "'_FIT_ ' ";
CHAR8 mFitSignatureInHeader[] = "' ' ";
CHAR8 *
FitTypeToStr (
IN FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry
)
{
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 " ";
}
}
/**
Print Fit table in flash image.
@param FvBuffer FvRecovery binary buffer.
@param FvSize FvRecovery size.
@return None
**/
VOID
PrintFitTable (
IN UINT8 *FvBuffer,
IN UINT32 FvSize
)
{
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.
@return none
**/
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
@return none
**/
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 ",
};
/**
DumpAcm information
@param Acm - ACM buffer
@retval None
**/
VOID
DumpAcm (
IN ACM_FORMAT *Acm
)
{
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; //add public key size (taken from header variable * 4) to buffer.
//add signature size to pointer.
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 if ((Acm->HeaderVersion == ACM_HEADER_VERSION_4) || (Acm->HeaderVersion == ACM_HEADER_VERSION_5)) {
Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
Buffer += ACM_XMSS_PUBLIC_KEY_SIZE;
Buffer += ACM_XMSS_SIGNATURE_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->HeaderVersion == ACM_HEADER_VERSION_4) || (Acm->HeaderVersion == ACM_HEADER_VERSION_5)) {
Buffer += 60; //add reserved bytes.
}
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"
);
}
/**
Get ACM FMS information.
@param Acm ACM buffer.
@param AcmFms Get ACM FMS.
@param AcmMask Get ACM Mask.
@retval NULL
**/
VOID
GetAcmFms(
IN ACM_FORMAT *Acm,
OUT UINT32 *AcmFms,
OUT UINT32 *AcmMask
)
{
UINT32 FmsOffset = 0;
UINT32 TmpFms = 0;
UINT32 TmpMask = 0;
UINT32 Index = 0;
PROCESSOR_ID_LIST *ProcessorIdList = NULL;
if ((Acm == NULL) || (AcmFms == NULL) || (AcmMask == NULL))
return;
*AcmFms = 0;
*AcmMask = 0;
switch (Acm->HeaderVersion) {
case ACM_HEADER_VERSION_3:
FmsOffset = *(UINT32*)((UINT8*)Acm + 0x6E8); //AcmInfoTable at 0x6C0, +0x28 for ProcessorIdList
break;
case ACM_HEADER_VERSION_4:
case ACM_HEADER_VERSION_5:
FmsOffset = *(UINT32*)((UINT8*)Acm + 0x1CA8); //AcmInfoTable at 0x1C80, +0x28 for ProcessorIdList
break;
default:
return;
}
ProcessorIdList = (PROCESSOR_ID_LIST *)((UINT8*)Acm + FmsOffset);
if (ProcessorIdList->Count > 0) {
TmpFms = ProcessorIdList->ProcessorID[0].FMS;
*AcmFms = TmpFms;
*AcmMask = DEFAULT_ACM_EXTENDED_MASK;
}
for (Index = 1; Index < ProcessorIdList->Count; Index++) {
TmpMask = (TmpFms ^ ProcessorIdList->ProcessorID[Index].FMS);
TmpFms &= ProcessorIdList->ProcessorID[Index].FMS;
}
*AcmMask = ~TmpMask;
return;
}
/**
Check Acm information.
@param Acm ACM buffer.
@param AcmMaxSize ACM max size.
@retval TRUE ACM is valid.
@retval FALSE ACM is invalid.
**/
BOOLEAN
CheckAcm (
IN ACM_FORMAT *Acm,
IN UINTN AcmMaxSize
)
{
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;
}
//move buffer pointer to address past generic ACM header (post scratchsize)
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 if ((Acm->HeaderVersion == ACM_HEADER_VERSION_4) || (Acm->HeaderVersion == ACM_HEADER_VERSION_5)) {
Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
Buffer += ACM_XMSS_PUBLIC_KEY_SIZE;
Buffer += ACM_XMSS_SIGNATURE_SIZE;
}
else {
Buffer += 4;
Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
}
Buffer += Acm->ScratchSize * 4;
if ((Acm->HeaderVersion == ACM_HEADER_VERSION_4) || (Acm->HeaderVersion == ACM_HEADER_VERSION_5)) {
Buffer += 60; //add reserved bytes.
}
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;
}
/**
Fill the FIT table information to FvRecovery.
@param FvBuffer FvRecovery binary buffer.
@param FvSize FvRecovery size.
@param FitTableOffset The offset of FIT table in FvRecovery file.
@retval None
**/
VOID
FillFitTable (
IN UINT8 *FvBuffer,
IN UINT32 FvSize,
IN UINT8 *FitTableOffset
)
{
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
UINT32 FitIndex;
UINT32 FitEntrySizeValue;
UINT32 Index;
UINT8 Checksum;
UINTN SubIndex;
FIT_TABLE_CONTEXT_ENTRY TempContextEntry;
FIRMWARE_INTERFACE_TABLE_ENTRY TempTableEntry;
PROCESSOR_ID FMS;
PROCESSOR_ID FMSMask;
//
// 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
//
FitEntrySizeValue = gFitTableContext.FitEntryNumber;
FitEntry[FitIndex].Address = *(UINT64 *)"_FIT_ ";
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
FitEntry[FitIndex].Rsvd = 0;
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++) {
FitEntrySizeValue = 0; // gFitTableContext.Microcode[Index].Size / 16
FitEntry[FitIndex].Address = gFitTableContext.Microcode[Index].Address;
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
FitEntry[FitIndex].Rsvd = 0;
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
//
for (Index = 0; Index < gFitTableContext.StartupAcmNumber; Index++) {
if (gFitTableContext.StartupAcm[Index].Version == STARTUP_ACM_FIT_ENTRY_200_VERSION) {
printf("ACM version 0x200\n");
FMS.Uint32 = gFitTableContext.StartupAcm[Index].FMS;
FMSMask.Uint32 = gFitTableContext.StartupAcm[Index].FMSMask;
printf("ACM FMS:%08x\n", FMS.Uint32);
printf("ACM FMSMask:%08x\n", FMSMask.Uint32);
FitEntry[FitIndex].Address = gFitTableContext.StartupAcm[Index].Address;
FitEntry[FitIndex].Size[0] = NIBBLES_TO_BYTE (FMS.Bits.Family, FMS.Bits.Model);
FitEntry[FitIndex].Size[1] = NIBBLES_TO_BYTE (FMS.Bits.ExtendedModel, FMS.Bits.Type);
FitEntry[FitIndex].Size[2] = NIBBLES_TO_BYTE (FMSMask.Bits.Family, FMSMask.Bits.Model);
FitEntry[FitIndex].Rsvd = NIBBLES_TO_BYTE (FMSMask.Bits.ExtendedModel, FMSMask.Bits.Type);
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.StartupAcm[Index].Version;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_STARTUP_ACM;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = NIBBLES_TO_BYTE (FMSMask.Bits.ExtendedFamily, FMS.Bits.ExtendedFamily);
} else {
FitEntrySizeValue = 0; // gFitTableContext.StartupAcm.Size / 16
FitEntry[FitIndex].Address = gFitTableContext.StartupAcm[Index].Address;
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
FitEntry[FitIndex].Rsvd = 0;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.StartupAcm[Index].Version;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_STARTUP_ACM;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
}
FitIndex++;
}
for (Index = 0; Index < gFitTableContext.MmcFwNumber; Index++) {
FitEntrySizeValue = 0; // gFitTableContext.MMCVersion.Size / 16
FitEntry[FitIndex].Address = gFitTableContext.MmcFw[Index].Address;
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
FitEntry[FitIndex].Rsvd = 0;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.MmcFw[Index].Version;
FitEntry[FitIndex].Type = 0x5;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 4.5. DiagnosticAcm
//
if (gFitTableContext.DiagnstAcm.Address != 0) {
if (gFitTableContext.DiagnstAcmVersion == STARTUP_ACM_FIT_ENTRY_200_VERSION) {
printf("DiagnstAcmACM version 0x200\n");
FMS.Uint32 = gFitTableContext.DiagnstAcm.FMS;
FMSMask.Uint32 = gFitTableContext.DiagnstAcm.FMSMask;
FitEntry[FitIndex].Address = gFitTableContext.DiagnstAcm.Address;
FitEntry[FitIndex].Size[0] = NIBBLES_TO_BYTE (FMS.Bits.Family, FMS.Bits.Model);
FitEntry[FitIndex].Size[1] = NIBBLES_TO_BYTE (FMS.Bits.ExtendedModel, FMS.Bits.Type);
FitEntry[FitIndex].Size[2] = NIBBLES_TO_BYTE (FMSMask.Bits.Family, FMSMask.Bits.Model);
FitEntry[FitIndex].Rsvd = NIBBLES_TO_BYTE (FMSMask.Bits.ExtendedModel, FMSMask.Bits.Type);
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.DiagnstAcmVersion;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_DIAGNST_ACM;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = NIBBLES_TO_BYTE (FMSMask.Bits.ExtendedFamily, FMS.Bits.ExtendedFamily);
} else {
printf("DiagnstAcmACM version 0x100\n");
FitEntrySizeValue = 0; // gFitTableContext.DiagnstAcmVersion.Size / 16
FitEntry[FitIndex].Address = gFitTableContext.DiagnstAcm.Address;
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
FitEntry[FitIndex].Rsvd = 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. (4) Bootable BootPolicy Data
//
if (gFitTableContext.ProtBootPolicy.Address != 0) {
FitEntry[FitIndex].Address = gFitTableContext.ProtBootPolicy.Address;
FitEntry[FitIndex].Size[0] = (UINT8) (gFitTableContext.ProtBootPolicy.Size);
FitEntry[FitIndex].Size[1] = (UINT8) (gFitTableContext.ProtBootPolicy.Size >> 8);
FitEntry[FitIndex].Size[2] = (UINT8) (gFitTableContext.ProtBootPolicy.Size >> 16);
FitEntry[FitIndex].Rsvd = 0;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.ProtBootPolicy.Version;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_PROT_BOOT_POLICY;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 6. BiosModule
//
//
// BiosModule segments order needs to be put from low address 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++) {
FitEntrySizeValue = gFitTableContext.BiosModule[Index].Size / 16;
FitEntry[FitIndex].Address = gFitTableContext.BiosModule[Index].Address;
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
FitEntry[FitIndex].Rsvd = 0;
FitEntry[FitIndex].Version = (UINT16)gFitTableContext.BiosModuleVersion;
FitEntry[FitIndex].Type = FIT_TABLE_TYPE_BIOS_MODULE;
FitEntry[FitIndex].C_V = 0;
FitEntry[FitIndex].Checksum = 0;
FitIndex++;
}
//
// 7. Optional module
//
for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) {
FitEntrySizeValue = gFitTableContext.OptionalModule[Index].Size;
FitEntry[FitIndex].Address = gFitTableContext.OptionalModule[Index].Address;
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
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++;
}
//
// 8. Port module
//
for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
FitEntrySizeValue = 0;
FitEntry[FitIndex].Address = gFitTableContext.PortModule[Index].Address + ((UINT64)gFitTableContext.PortModule[Index].Size << 32);
FitEntry[FitIndex].Size[0] = (UINT8)FitEntrySizeValue;
FitEntry[FitIndex].Size[1] = (UINT8)(FitEntrySizeValue >> 8);
FitEntry[FitIndex].Size[2] = (UINT8)(FitEntrySizeValue >> 16);
FitEntry[FitIndex].Rsvd = 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;
}
/**
Clear the FIT table information to Fvrecovery.
@param FvBuffer - Fvrecovery binary buffer.
@param FvSize - Fvrecovery size.
@retval None
**/
VOID
ClearFitTable (
IN UINT8 *FvBuffer,
IN UINT32 FvSize
)
{
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_FSP_BOOT_MANIFEST:
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);
}
}
/**
Read input file.
@param FileName The input file name.
@param FileData The input file data.
@paramFileSize The input file size.
@retval STATUS_SUCCESS Write file data successfully.
@retval STATUS_ERROR The file data is not written.
**/
STATUS
WriteOutputFile (
IN CHAR8 *FileName,
IN UINT8 *FileData,
IN UINT32 FileSize
)
{
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
GetFvAcmSizeFromFd(
IN UINT8 *FdBuffer,
IN UINT32 FdFileSize
)
/**
Get FV_ACM Size information from Fd file.
@param FdBuffer Fd file buffer.
@param FdFileSize Fd file size.
@retval FvACM size
**/
{
UINT8 *FileBuffer = NULL;
UINT32 FvAcmSize = 0;
EFI_GUID ACMGuid = ACMFV_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, &ACMGuid, &FileLength) != NULL) {
//
// Found the ACM
//
FvAcmSize = FvLength;
}
//
// 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 FvAcmSize;
}
/**
Get FvRecovery information from Fd file.
@param FdBuffer Fd file buffer.
@param FdFileSize Fd file size.
@param FvRecovery FvRecovery pointer in Fd file buffer
@retval FvRecovery file size
**/
UINT32
GetFvRecoveryInfoFromFd (
IN UINT8 *FdBuffer,
IN UINT32 FdFileSize,
OUT UINT8 **FvRecovery
)
{
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;
}
/**
Get FMS information from FIT Entry.
Note: Since FIT entry not record all the processor ID information.
The value would not the same as the real value.
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
| Byte | 15 | 14 | 13:12 | 11 |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
|Bit Fields| [7:4] | [3:0] | [7:7] | [6:0] | [7:4] | [3:0] | [7:4] | [3:0] |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
| Ver. 100 | Checksum | C_V | Type | Version | Reserved |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
| Ver. 200 | FMSMask | FMS | C_V | Type | Version | FMSMask | FMSMask |
| | ExtFamily | ExtFamily | | | | ExtModel | Type |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
| Byte | 10 | 9 | 8 | 7:0 |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
|Bit Fields| [7:4] | [3:0] | [7:4] | [3:0] | [7:4] | [3:0] | [7:4] | [3:0] |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
| Ver. 100 | Size[2] | Size[1] | Size[0] | Address |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
| Ver. 200 | FMSMask | FMSMask | FMS | FMS | FMS | FMS | Address |
| | Family | Model | ExtModel | Type | Family | Model | |
+----------+-----------------------+-----------------------+-----------------------+-----------------------+
@param FitEntry FIT entry information.
@param FMS Processor ID information.
@param FMSMask Processor ID mask information.
@retval None
**/
void
GetFMSFromFitEntry (
IN FIRMWARE_INTERFACE_TABLE_ENTRY FitEntry,
IN OUT PROCESSOR_ID *FMS,
IN OUT PROCESSOR_ID *FMSMask
)
{
FMS->Bits.Family = (FitEntry.Size[0] & 0xF0) >> 4;
FMS->Bits.Model = (FitEntry.Size[0] & 0x0F);
FMS->Bits.ExtendedModel = (FitEntry.Size[1] & 0xF0) >> 4;
FMS->Bits.Type = (FitEntry.Size[1] & 0x0F);
FMS->Bits.ExtendedFamily = (FitEntry.Checksum & 0x0F);
FMSMask->Bits.Family = (FitEntry.Size[2] & 0xF0) >> 4;
FMSMask->Bits.Model = (FitEntry.Size[2] & 0x0F);
FMSMask->Bits.ExtendedModel = (FitEntry.Rsvd & 0xF0) >> 4;
FMSMask->Bits.Type = (FitEntry.Rsvd & 0x0F);
FMSMask->Bits.ExtendedFamily = (FitEntry.Checksum & 0xF0) >> 4;
}
/**
Get the FIT table information from Fvrecovery.
@param FvBuffer Fvrecovery binary buffer.
@param FvSize Fvrecovery size.
@retval 0 - Fit Table not found
**/
UINT32
GetFitEntryInfo (
IN UINT8 *FvBuffer,
IN UINT32 FvSize
)
{
FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
UINT32 FitEntrySizeValue;
UINT32 FitIndex;
UINT32 FitTableOffset;
PROCESSOR_ID FMS;
PROCESSOR_ID FMSMask;
FMS.Uint32 = 0;
FMSMask.Uint32 = 0;
//
// 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;
}
FitEntrySizeValue = (((UINT32)FitEntry[FitIndex].Size[2]) << 16) + (((UINT32)FitEntry[FitIndex].Size[1]) << 8) + ((UINT32)FitEntry[FitIndex].Size[0]);
gFitTableContext.FitEntryNumber = FitEntrySizeValue;
gFitTableContext.FitHeaderVersion = FitEntry[FitIndex].Version;
//
// 3. FitEntry
//
FitIndex++;
for (; FitIndex < gFitTableContext.FitEntryNumber; FitIndex++) {
FitEntrySizeValue = (((UINT32)FitEntry[FitIndex].Size[2]) << 16) + (((UINT32)FitEntry[FitIndex].Size[1]) << 8) + ((UINT32)FitEntry[FitIndex].Size[0]);
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[gFitTableContext.StartupAcmNumber].Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Size = FitEntrySizeValue;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Type = FitEntry[FitIndex].Type;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Version = FitEntry[FitIndex].Version;
if (gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].Version == STARTUP_ACM_FIT_ENTRY_200_VERSION) {
GetFMSFromFitEntry (FitEntry[FitIndex], &FMS, &FMSMask);
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].FMS = FMS.Uint32;
gFitTableContext.StartupAcm[gFitTableContext.StartupAcmNumber].FMSMask = FMSMask.Uint32;
}
gFitTableContext.StartupAcmNumber++;
break;
case FIT_TABLE_TYPE_PROT_BOOT_POLICY:
gFitTableContext.ProtBootPolicy.Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.ProtBootPolicy.Version = FitEntry[FitIndex].Version;
gFitTableContext.ProtBootPolicy.Size = GetFirmwareInterfaceTableEntrySize (&FitEntry[FitIndex]);
break;
case FIT_TABLE_TYPE_MMC_FW:
gFitTableContext.MmcFw[gFitTableContext.MmcFwNumber].Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.MmcFw[gFitTableContext.MmcFwNumber].Version = FitEntry[FitIndex].Version;
gFitTableContext.MmcFwNumber++;
break;
case FIT_TABLE_TYPE_BIOS_MODULE:
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FitEntrySizeValue * 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 = FitEntrySizeValue;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = FitEntry[FitIndex].Version;
gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = FitEntry[FitIndex].Type;
gFitTableContext.OptionalModuleNumber ++;
break;
}
}
return gFitTableContext.FitEntryNumber;
}
/**
Main function for FitGen.
@param argc Number of command line parameters.
@param argv Array of pointers to parameter strings.
@retval STATUS_SUCCESS Utility exits successfully.
@retval STATUS_ERROR Some error occurred during execution.
**/
STATUS
FitGen (
IN INTN argc,
IN CHAR8 **argv
)
{
UINT32 FvRecoveryFileSize;
UINT8 *FileBuffer;
UINT8 *FileBufferRaw;
UINTN FitEntryNumber;
UINT8 *FitTableOffset;
STATUS Status;
UINT32 FitTableSize;
BOOLEAN IsFv;
UINT8 *FdFileBuffer;
UINT32 FdFileSize;
UINT8 *AcmBuffer;
INTN Index = 0;
UINT32 FixedFitLocation;
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++;
FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
FitTableSize += FIT_ALIGNMENT;
FitTableSize &= ~FIT_ALIGNMENT;
//
// Step 3: Get enough space for FIT
//
FixedFitLocation = GetFixedFitLocation (argc, argv);
if (FixedFitLocation != 0 &&
(FixedFitLocation < TOP_FLASH_ADDRESS - FdFileSize || FixedFitLocation + FitTableSize > TOP_FLASH_ADDRESS)) {
//
// FixedFitLocation is out of the input FD region, still find space from FvRecovery
//
FixedFitLocation = 0;
printf ("The fixed FIT location is not in valid flash region, find space from FvRecovery ...\n");
}
FitTableOffset = GetFreeSpaceForFit (FileBuffer, FvRecoveryFileSize, FitTableSize, FixedFitLocation);
if (FitTableOffset == NULL) {
printf ("Error - FitTableOffset is NULL\n");
return STATUS_ERROR;
}
CheckOverlap (
MEMORY_TO_FLASH (FitTableOffset, FdFileBuffer, FdFileSize),
FitTableSize
);
//
// Get ACM buffer
//
for (Index = 0; Index < (INTN)gFitTableContext.StartupAcmNumber; Index ++) {
printf("ACM address:%08x\n", gFitTableContext.StartupAcm[Index].Address);
printf("ACM size:%08x\n", gFitTableContext.StartupAcm[Index].Size);
if (gFitTableContext.StartupAcm[Index].Address != 0) {
printf("get AcmBuffer\n");
AcmBuffer = FLASH_TO_MEMORY(gFitTableContext.StartupAcm[Index].Address, FdFileBuffer, FdFileSize);
if ((AcmBuffer < FdFileBuffer) || (AcmBuffer + gFitTableContext.StartupAcm[Index].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[Index].Size)) {
DumpAcm((ACM_FORMAT *)AcmBuffer);
if (gFitTableContext.StartupAcm[Index].Version >= 0x200) {
if ((gFitTableContext.StartupAcm[Index].FMS == 0) && (gFitTableContext.StartupAcm[Index].FMSMask == 0)) {
//
// FMS and FMSMask is not assigned via -I argument. Get it from ACM
//
GetAcmFms((ACM_FORMAT *)AcmBuffer, &gFitTableContext.StartupAcm[Index].FMS, &gFitTableContext.StartupAcm[Index].FMSMask);
printf("ACM FMS:%08x\n", gFitTableContext.StartupAcm[Index].FMS);
printf("ACM FMS Mask:%08x\n", gFitTableContext.StartupAcm[Index].FMSMask);
}
}
}
else {
if (Index == 0) {
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;
}
/**
View function for FitGen.
@param argc Number of command line parameters.
@param argv Array of pointers to parameter strings
@retval STATUS_SUCCESS Utility exits successfully.
@retval STATUS_ERROR Some error occurred during execution.
**/
STATUS
FitView (
IN INTN argc,
IN CHAR8 **argv
)
{
UINT32 FvRecoveryFileSize;
UINT8 *FileBuffer;
UINT8 *FileBufferRaw = NULL;
STATUS Status;
FILE *FpIn;
UINT32 FlashValidSig = 0;
UINT32 Frba;
UINT32 BiosRegionBaseOffset;
FLASH_MAP_0_REGISTER FlashMap0;
FLASH_REGION_1_BIOS_REGISTER FlashRegion1;
//
// 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);
Status = STATUS_ERROR;
goto exitFunc;
}
} else {
Error (NULL, 0, 0, "Invalid view option: ", "%s", argv[3]);
Status = STATUS_ERROR;
goto exitFunc;
}
//
//Check the File Path
//
if (!CheckPath (argv[2])) {
Error (NULL, 0, 0, "File path is invalid!", NULL);
Status = STATUS_ERROR;
goto exitFunc;
}
//
// Open the Input file
//
if ((FpIn = fopen (argv[2], "rb")) == NULL) {
Error (NULL, 0, 0, "Unable open the file!", NULL);
Status = STATUS_WARNING;
goto exitFunc;
}
//
//Seek and read the Flash Valid Signature;
//
fseek (FpIn, FLVALSIG_BASE_OFFSET, SEEK_SET);
fread (&FlashValidSig, 4, 1, FpIn);
if (FlashValidSig == FLASH_VALID_SIGNATURE) {
//
//Seek and read the Flash Map 0 Register;
//
fseek (FpIn, FLMAP0_BASE_OFFSET, SEEK_SET);
fread (&FlashMap0, 4, 1, FpIn);
Frba = FlashMap0.Frba << 4 & 0xFF0; //FRBA identifies address bits [11:4] for the region portion of the flashdescriptor, bits [26:12] and bits [3:0] are 0
//
//Seek and read the Flash Region 1 (BIOS) Register;
//
BiosRegionBaseOffset = Frba + 0x4;
fseek (FpIn, BiosRegionBaseOffset, SEEK_SET);
fread (&FlashRegion1, 4, 1, FpIn);
FileBuffer = (UINT8 *)(FileBuffer + (FlashRegion1.RegionBase << 12)); // RegionBase specifies address bits [26:12] for the Region Base.
FvRecoveryFileSize = ((FlashRegion1.RegionLimit << 12 | 0xFFF) + 1) - (FlashRegion1.RegionBase << 12); //RegionLimit specifies bits [26:12] of the ending address for this region, bits [11:0] are assumed to be FFFh.
}
//
// Close the Input file
//
fclose (FpIn);
//
// For debug
//
PrintFitTable (FileBuffer, FvRecoveryFileSize);
exitFunc:
if (FileBufferRaw != NULL) {
free ((VOID *)FileBufferRaw);
}
return Status;
}
/**
Main function.
@param argc Number of command line parameters.
@param argv Array of pointers to parameter strings
@retval STATUS_SUCCESS Utility exits successfully.
@retval STATUS_ERROR Some error occurred during execution.
**/
int
main (
int argc,
char **argv
)
{
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;
}
}
/**
Convert hex string to uint
@param str The string
@retval Integer value
**/
unsigned int
xtoi (
char *str
)
{
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;
}