From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: shenglei.zhang@intel.com) Received: from mga01.intel.com (mga01.intel.com []) by groups.io with SMTP; Thu, 20 Jun 2019 18:27:03 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 Jun 2019 18:27:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,398,1557212400"; d="scan'208";a="358723224" Received: from shenglei-dev.ccr.corp.intel.com ([10.239.158.52]) by fmsmga005.fm.intel.com with ESMTP; 20 Jun 2019 18:27:01 -0700 From: "Zhang, Shenglei" To: devel@edk2.groups.io Cc: Bob Feng , Liming Gao Subject: [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Date: Fri, 21 Jun 2019 09:26:42 +0800 Message-Id: <20190621012643.9352-6-shenglei.zhang@intel.com> X-Mailer: git-send-email 2.18.0.windows.1 In-Reply-To: <20190621012643.9352-1-shenglei.zhang@intel.com> References: <20190621012643.9352-1-shenglei.zhang@intel.com> The utility of this tool is part of build process for IA32/X64 FD. It generates FIT table. https://bugzilla.tianocore.org/show_bug.cgi?id=1849 Cc: Bob Feng Cc: Liming Gao Signed-off-by: Shenglei Zhang --- Silicon/Intel/Tools/FitGen/FitGen.c | 3137 ++++++++++++++++++++++++ Silicon/Intel/Tools/FitGen/FitGen.h | 48 + Silicon/Intel/Tools/FitGen/GNUmakefile | 16 + Silicon/Intel/Tools/FitGen/Makefile | 17 + 4 files changed, 3218 insertions(+) create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile create mode 100644 Silicon/Intel/Tools/FitGen/Makefile diff --git a/Silicon/Intel/Tools/FitGen/FitGen.c b/Silicon/Intel/Tools/FitGen/FitGen.c new file mode 100644 index 0000000000..faf9880060 --- /dev/null +++ b/Silicon/Intel/Tools/FitGen/FitGen.c @@ -0,0 +1,3137 @@ +/**@file +This utility is part of build process for IA32/X64 FD. +It generates FIT table. + +Copyright (c) 2010-2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FitGen.h" + +// +// FIT spec +// +#pragma pack (1) +typedef struct { + UINT64 Address; + UINT8 Size[3]; + UINT8 Rsvd; + UINT16 Version; + UINT8 Type:7; + UINT8 C_V:1; + UINT8 Checksum; +} FIRMWARE_INTERFACE_TABLE_ENTRY; + +// +// Struct for policy +// +typedef struct { + UINT16 IndexPort; + UINT16 DataPort; + UINT8 Width; + UINT8 Bit; + UINT16 Index; + UINT8 Size[3]; + UINT8 Rsvd; + UINT16 Version; // == 0 + UINT8 Type:7; + UINT8 C_V:1; + UINT8 Checksum; +} FIRMWARE_INTERFACE_TABLE_ENTRY_PORT; + +#define FIT_ALIGNMENT 0x3F // 0xF is required previously, but if we need exclude FIT, we must set 64 bytes alignment. +#define BIOS_MODULE_ALIGNMENT 0x3F // 64 bytes for AnC +#define MICROCODE_ALIGNMENT 0x7FF + +#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE 256 +#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE 384 + +#define ACM_HEADER_VERSION_3 (3 << 16) +#define ACM_MODULE_TYPE_CHIPSET_ACM 2 +#define ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET 0x1 +#define ACM_MODULE_SUBTYPE_ANC_MODULE 0x2 +#define ACM_MODULE_FLAG_PREPRODUCTION 0x4000 +#define ACM_MODULE_FLAG_DEBUG_SIGN 0x8000 + + +typedef struct { + UINT16 ModuleType; + UINT16 ModuleSubType; + UINT32 HeaderLen; + UINT32 HeaderVersion; + UINT16 ChipsetID; + UINT16 Flags; + UINT32 ModuleVendor; + UINT32 Date; + UINT32 Size; + UINT16 TxtSvn; + UINT16 SeSvn; + UINT32 CodeControl; + UINT32 ErrorEntryPoint; + UINT32 GDTLimit; + UINT32 GDTBasePtr; + UINT32 SegSel; + UINT32 EntryPoint; + UINT8 Rsvd2[64]; + UINT32 KeySize; // 64 + UINT32 ScratchSize; // 2 * KeySize + 15 +//UINT8 RSAPubKey[64 * 4]; // KeySize * 4 +//UINT32 RSAPubExp; +//UINT8 RSASig[256]; + // End of AC module header +//UINT8 Scratch[(64 * 2 + 15) * 4]; // ScratchSize * 4 + // User Area +//UINT8 UserArea[1]; +} ACM_FORMAT; + +#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_3 0x03 +#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_4 0x04 + +#define CHIPSET_ACM_INFORMATION_TABLE_VERSION CHIPSET_ACM_INFORMATION_TABLE_VERSION_3 + +#define CHIPSET_ACM_INFORMATION_TABLE_GUID_V03 \ + { 0x7FC03AAA, 0x18DB46A7, 0x8F69AC2E, 0x5A7F418D } + +#define CHIPSET_ACM_TYPE_BIOS 0 +#define CHIPSET_ACM_TYPE_SINIT 1 + +typedef struct { + UINT32 Guid0; + UINT32 Guid1; + UINT32 Guid2; + UINT32 Guid3; +} ACM_GUID; + +typedef struct { + ACM_GUID Guid; + UINT8 ChipsetACMType; + UINT8 Version; + UINT16 Length; + UINT32 ChipsetIDList; + UINT32 OsSinitTableVer; + UINT32 MinMleHeaderVer; +//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) + UINT32 Capabilities; + UINT8 AcmVersion; + UINT8 AcmRevision[3]; +//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) + UINT32 ProcessorIDList; +//#endif +//#endif +} CHIPSET_ACM_INFORMATION_TABLE; + +#define ACM_CHIPSET_ID_REVISION_ID_MAKE 0x1 + +typedef struct { + UINT32 Flags; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevisionID; + UINT8 Reserved[6]; +} ACM_CHIPSET_ID; + +typedef struct { + UINT32 Count; + ACM_CHIPSET_ID ChipsetID[1]; +} CHIPSET_ID_LIST; + +typedef struct { + UINT32 FMS; + UINT32 FMSMask; + UINT64 PlatformID; + UINT64 PlatformMask; +} ACM_PROCESSOR_ID; + +typedef struct { + UINT32 Count; + ACM_PROCESSOR_ID ProcessorID[1]; +} PROCESSOR_ID_LIST; + +#pragma pack () + + +ACM_GUID mChipsetAcmInformationTableGuid03 = CHIPSET_ACM_INFORMATION_TABLE_GUID_V03; + + +// +// BIOS INFO data structure +// This is self contained data structure for BIOS info +// +#pragma pack (1) +#define BIOS_INFO_SIGNATURE SIGNATURE_64 ('$', 'B', 'I', 'O', 'S', 'I', 'F', '$') +typedef struct { + UINT64 Signature; + UINT32 EntryCount; + UINT32 Reserved; +//BIOS_INFO_STRUCT Struct[EntryCount]; +} BIOS_INFO_HEADER; + +// +// BIOS_INFO_STRUCT attributes +// bits[0:3] means general attributes +// bits[4:7] means type specific attributes +// +#define BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT 0x01 +#define BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION 0x10 +#define BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB 0x10 + +typedef struct { + // + // FitTable entry type + // + UINT8 Type; + // + // BIOS_INFO_STRUCT attributes + // + UINT8 Attributes; + // + // FitTable entry version + // + UINT16 Version; + // + // FitTable entry real size + // + UINT32 Size; + // + // FitTable entry address + // + UINT64 Address; +} BIOS_INFO_STRUCT; + +#pragma pack () + +#define MAX_BIOS_MODULE_ENTRY 0x20 +#define MAX_MICROCODE_ENTRY 0x20 +#define MAX_OPTIONAL_ENTRY 0x20 +#define MAX_PORT_ENTRY 0x20 + +#define DEFAULT_FIT_TABLE_POINTER_OFFSET 0x40 +#define DEFAULT_FIT_ENTRY_VERSION 0x0100 + +#define MEMORY_TO_FLASH(FileBuffer, FvBuffer, FvSize) \ + (UINTN)(0x100000000 - ((UINTN)(FvBuffer) + (UINTN)(FvSize) - (UINTN)(FileBuffer))) +#define FLASH_TO_MEMORY(Address, FvBuffer, FvSize) \ + (VOID *)(UINTN)((UINTN)(FvBuffer) + (UINTN)(FvSize) - (0x100000000 - (UINTN)(Address))) + +#define FIT_TABLE_TYPE_HEADER 0 +#define FIT_TABLE_TYPE_MICROCODE 1 +#define FIT_TABLE_TYPE_STARTUP_ACM 2 +#define FIT_TABLE_TYPE_BIOS_MODULE 7 +#define FIT_TABLE_TYPE_TPM_POLICY 8 +#define FIT_TABLE_TYPE_BIOS_POLICY 9 +#define FIT_TABLE_TYPE_TXT_POLICY 10 +#define FIT_TABLE_TYPE_KEY_MANIFEST 11 +#define FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST 12 +#define FIT_TABLE_TYPE_BIOS_DATA_AREA 13 +#define FIT_TABLE_TYPE_CSE_SECURE_BOOT 16 + +typedef struct { + UINT32 Type; + UINT32 Address; + UINT32 Size; + UINT32 Version; // Used by OptionalModule and PortModule only +} FIT_TABLE_CONTEXT_ENTRY; + +typedef struct { + BOOLEAN Clear; + UINT32 FitTablePointerOffset; + UINT32 FitTablePointerOffset2; + UINT32 FitEntryNumber; + UINT32 BiosModuleNumber; + UINT32 MicrocodeNumber; + UINT32 OptionalModuleNumber; + UINT32 PortModuleNumber; + UINT32 GlobalVersion; + UINT32 FitHeaderVersion; + FIT_TABLE_CONTEXT_ENTRY StartupAcm; + UINT32 StartupAcmVersion; + FIT_TABLE_CONTEXT_ENTRY BiosModule[MAX_BIOS_MODULE_ENTRY]; + UINT32 BiosModuleVersion; + FIT_TABLE_CONTEXT_ENTRY Microcode[MAX_MICROCODE_ENTRY]; + BOOLEAN MicrocodeAlignment; + UINT32 MicrocodeVersion; + FIT_TABLE_CONTEXT_ENTRY OptionalModule[MAX_OPTIONAL_ENTRY]; + FIT_TABLE_CONTEXT_ENTRY PortModule[MAX_PORT_ENTRY]; +} FIT_TABLE_CONTEXT; + +FIT_TABLE_CONTEXT gFitTableContext = {0}; + +unsigned int +xtoi ( + char *str + ); + +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + Displays the standard utility information to STDOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ( + "%s - Tiano IA32/X64 FIT table generation Utility."" Version %i.%i\n\n", + UTILITY_NAME, + UTILITY_MAJOR_VERSION, + UTILITY_MINOR_VERSION + ); +} + +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + Displays the utility usage syntax to STDOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ("Usage (generate): %s [-D] InputFvRecoveryFile OutputFvRecoveryFile\n" + "\t[-V ]\n" + "\t[-F ] [-F ] [-V ]\n" + "\t[-NA]\n" + "\t[-CLEAR]\n" + "\t[-I ]\n" + "\t[-S |] [-V ]\n" + "\t[-B ] [-B ...] [-V ]\n" + "\t[-M ] [-M ...]|[-U ||] [-V ]\n" + "\t[-O RecordType ||| [-V ]] [-O ... [-V ...]]\n" + "\t[-P RecordType [-V ]] [-P ... [-V ...]]\n" + , UTILITY_NAME); + printf (" Where:\n"); + printf ("\t-D - It is FD file instead of FV file. (The tool will search FV file)\n"); + printf ("\tInputFvRecoveryFile - Name of the input FvRecovery.fv file.\n"); + printf ("\tOutputFvRecoveryFile - Name of the output FvRecovery.fv file.\n"); + printf ("\tFitTablePointerOffset - FIT table pointer offset. 0x%x as default. 0x18 for current soon to be obsoleted CPUs. User can set both.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET); + printf ("\tBiosInfoGuid - Guid of BiosInfo Module. If this module exists, StartupAcm/Bios/Microcode can be optional.\n"); + printf ("\tStartupAcmAddress - Address of StartupAcm.\n"); + printf ("\tStartupAcmSize - Size of StartupAcm.\n"); + printf ("\tStartupAcmGuid - Guid of StartupAcm Module, if StartupAcm is in a BiosModule, it will be excluded form that.\n"); + printf ("\tBiosModuleAddress - Address of BiosModule. User should ensure there is no overlap.\n"); + printf ("\tBiosModuleSize - Size of BiosModule.\n"); + printf ("\tMicrocodeAddress - Address of Microcode.\n"); + printf ("\tMicrocodeSize - Size of Microcode.\n"); + printf ("\tMicrocodeFv - Name of Microcode.fv file.\n"); + printf ("\tMicrocodeBase - The base address of Microcode.fv in final FD image.\n"); + printf ("\tMicrocodeRegionOffset - Offset of Microcode region in input FD image.\n"); + printf ("\tMicrocodeRegionSize - Size of Microcode region in input FD image.\n"); + printf ("\tMicrocodeGuid - Guid of Microcode Module.\n"); + printf ("\t-NA - No 0x800 aligned Microcode requirement. No -NA means Microcode is 0x800 aligned.\n"); + printf ("\tRecordType - FIT entry record type. User should ensure it is ordered.\n"); + printf ("\tRecordDataAddress - FIT entry record data address.\n"); + printf ("\tRecordDataSize - FIT entry record data size.\n"); + printf ("\tRecordDataGuid - FIT entry record data GUID.\n"); + printf ("\tRecordBinFile - FIT entry record data binary file.\n"); + printf ("\tFitEntryDefaultVersion - The default version for all FIT table entries. 0x%04x is used if this is not specified.\n", DEFAULT_FIT_ENTRY_VERSION); + printf ("\tFitHeaderVersion - The version for FIT header. (Override default version)\n"); + printf ("\tStartupAcmVersion - The version for StartupAcm. (Override default version)\n"); + printf ("\tBiosModuleVersion - The version for BiosModule. (Override default version)\n"); + printf ("\tMicrocodeVersion - The version for Microcode. (Override default version)\n"); + printf ("\tRecordVersion - The version for Record. (Override default version)\n"); + printf ("\tIndexPort - The Index Port Number.\n"); + printf ("\tDataPort - The Data Port Number.\n"); + printf ("\tWidth - The Width of the port.\n"); + printf ("\tBit - The Bit Number of the port.\n"); + printf ("\tIndex - The Index Number of the port.\n"); + printf ("\nUsage (view): %s [-view] InputFile -F \n", UTILITY_NAME); + printf (" Where:\n"); + printf ("\tInputFile - Name of the input file.\n"); + printf ("\tFitTablePointerOffset - FIT table pointer offset from end of file. 0x%x as default.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET); + printf ("\nTool return values:\n"); + printf ("\tSTATUS_SUCCESS=%d, STATUS_WARNING=%d, STATUS_ERROR=%d\n", STATUS_SUCCESS, STATUS_WARNING, STATUS_ERROR); +} + +VOID * +SetMem ( + OUT VOID *Buffer, + IN UINTN Length, + IN UINT8 Value + ) +{ + // + // Declare the local variables that actually move the data elements as + // volatile to prevent the optimizer from replacing this function with + // the intrinsic memset() + // + volatile UINT8 *Pointer; + + Pointer = (UINT8*)Buffer; + while (Length-- > 0) { + *(Pointer++) = Value; + } + return Buffer; +} + +STATUS +ReadInputFile ( + IN CHAR8 *FileName, + OUT UINT8 **FileData, + OUT UINT32 *FileSize, + OUT UINT8 **FileBufferRaw OPTIONAL + ) +/*++ + +Routine Description: + + Read input file + +Arguments: + + FileName - The input file name + FileData - The input file data, the memory is aligned. + FileSize - The input file size + FileBufferRaw - The memory to hold input file data. The caller must free the memory. + +Returns: + + STATUS_SUCCESS - The file found and data read + STATUS_ERROR - The file data is not read + STATUS_WARNING - The file is not found + +--*/ +{ + FILE *FpIn; + UINT32 TempResult; + + // + // Open the Input FvRecovery.fv file + // + if ((FpIn = fopen (FileName, "rb")) == NULL) { + // + // Return WARNING, let caller make decision + // +// Error (NULL, 0, 0, "Unable to open file", FileName); + return STATUS_WARNING; + } + // + // Get the Input FvRecovery.fv file size + // + fseek (FpIn, 0, SEEK_END); + *FileSize = ftell (FpIn); + // + // Read the contents of input file to memory buffer + // + if (FileBufferRaw != NULL) { + *FileBufferRaw = (UINT8 *) malloc (*FileSize + 0x10000); + if (NULL == *FileBufferRaw) { + Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL); + fclose (FpIn); + return STATUS_ERROR; + } + TempResult = 0x10000 - (UINT32) ((UINTN)*FileBufferRaw & 0x0FFFF); + *FileData = (UINT8 *)((UINTN)*FileBufferRaw + TempResult); + } else { + *FileData = (UINT8 *) malloc (*FileSize); + if (NULL == *FileData) { + Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL); + fclose (FpIn); + return STATUS_ERROR; + } + } + fseek (FpIn, 0, SEEK_SET); + TempResult = fread (*FileData, 1, *FileSize, FpIn); + if (TempResult != *FileSize) { + Error (NULL, 0, 0, "Read input file error!", NULL); + if (FileBufferRaw != NULL) { + free ((VOID *)*FileBufferRaw); + } else { + free ((VOID *)*FileData); + } + fclose (FpIn); + return STATUS_ERROR; + } + + // + // Close the input FvRecovery.fv file + // + fclose (FpIn); + + return STATUS_SUCCESS; +} + +UINT8 * +FindNextFvHeader ( + IN UINT8 *FileBuffer, + IN UINTN FileLength + ) +/*++ + + Routine Description: + Find next FvHeader in the FileBuffer + + Parameters: + FileBuffer - The start FileBuffer which needs to be searched + FileLength - The whole File Length. + Return: + FvHeader - The FvHeader is found successfully. + NULL - The FvHeader is not found. + +--*/ +{ + UINT8 *FileHeader; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + UINT16 FileChecksum; + + FileHeader = FileBuffer; + for (; (UINTN)FileBuffer < (UINTN)FileHeader + FileLength; FileBuffer += 8) { + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer; + if (FvHeader->Signature == EFI_FVH_SIGNATURE) { + // + // potential candidate + // + + // + // Check checksum + // + if (FvHeader->FvLength > FileLength) { + continue; + } + if (FvHeader->HeaderLength >= FileLength) { + continue; + } + FileChecksum = CalculateChecksum16 ((UINT16 *)FileBuffer, FvHeader->HeaderLength / sizeof (UINT16)); + if (FileChecksum != 0) { + continue; + } + + // + // Check revision and reserved field + // +#if (PI_SPECIFICATION_VERSION < 0x00010000) + if ((FvHeader->Revision == EFI_FVH_REVISION) && + (FvHeader->Reserved[0] == 0) && + (FvHeader->Reserved[1] == 0) && + (FvHeader->Reserved[2] == 0) ){ + return FileBuffer; + } +#else + if ((FvHeader->Revision == EFI_FVH_PI_REVISION) && + (FvHeader->Reserved[0] == 0) ){ + return FileBuffer; + } +#endif + } + } + + return NULL; +} + +UINT8 * +FindFileFromFvByGuid ( + IN UINT8 *FvBuffer, + IN UINT32 FvSize, + IN EFI_GUID *Guid, + OUT UINT32 *FileSize + ) +/*++ + +Routine Description: + + Find File with GUID in an FV + +Arguments: + + FvBuffer - FV binary buffer + FvSize - FV size + Guid - File GUID value to be searched + FileSize - Guid File size + +Returns: + + FileLocation - Guid File location. + NULL - Guid File is not found. + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FFS_FILE_HEADER *FileHeader; + UINT64 FvLength; + EFI_GUID *TempGuid; + UINT8 *FixPoint; + UINT32 Offset; + UINT32 FileLength; + UINT32 FileOccupiedSize; + + // + // Find the FFS file + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader (FvBuffer, FvSize); + if (NULL == FvHeader) { + return NULL; + } + while (TRUE) { + FvLength = FvHeader->FvLength; + + // + // Prepare to walk the FV image + // + InitializeFvLib (FvHeader, (UINT32)FvLength); + + FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength); + Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader; + + while (Offset < FvLength) { + TempGuid = (EFI_GUID *)&(FileHeader->Name); + FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF; + FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8); + if ((CompareGuid (TempGuid, Guid)) == 0) { + // + // Good! Find it. + // + FixPoint = ((UINT8 *)FileHeader + sizeof(EFI_FFS_FILE_HEADER)); + // + // Find the position of file module, the offset + // between the position and the end of FvRecovery.fv file + // should not exceed 128kB to prevent reset vector from + // outside legacy E and F segment + // + if ((UINTN)FvHeader + FvLength - (UINTN)FixPoint > 0x20000) { + // printf ("WARNING: The position of file module is not in E and F segment!\n"); + // return NULL; + } + *FileSize = FileLength - sizeof(EFI_FFS_FILE_HEADER); + #if (PI_SPECIFICATION_VERSION < 0x00010000) + if (FileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + *FileSize -= sizeof(EFI_FFS_FILE_TAIL); + } + #endif + return FixPoint; + } + FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize); + Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader; + } + + // + // Not found, check next FV + // + if ((UINTN)FvBuffer + FvSize > (UINTN)FvHeader + FvLength) { + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader ((UINT8 *)FvHeader + (UINTN)FvLength, (UINTN)FvBuffer + FvSize - ((UINTN)FvHeader + (UINTN)FvLength)); + if (FvHeader == NULL) { + break; + } + } else { + break; + } + } + + // + // Not found + // + return NULL; +} + +BOOLEAN +IsGuidData ( + IN CHAR8 *StringData, + OUT EFI_GUID *Guid + ) +/*++ + +Routine Description: + + Check whether a string is a GUID + +Arguments: + + StringData - the String + Guid - Guid to hold the value + +Returns: + + TRUE - StringData is a GUID, and Guid field is filled. + FALSE - StringData is not a GUID + +--*/ +{ + if (strlen (StringData) != strlen ("00000000-0000-0000-0000-000000000000")) { + return FALSE; + } + if ((StringData[8] != '-') || + (StringData[13] != '-') || + (StringData[18] != '-') || + (StringData[23] != '-') ) { + return FALSE; + } + + StringToGuid (StringData, Guid); + + return TRUE; +} + +VOID +CheckOverlap ( + IN UINT32 Address, + IN UINT32 Size + ) +{ + INTN Index; + + for (Index = 0; Index < (INTN)gFitTableContext.BiosModuleNumber; Index ++) { + if ((gFitTableContext.BiosModule[Index].Address <= Address) && + ((gFitTableContext.BiosModule[Index].Size - Size) >= (Address - gFitTableContext.BiosModule[Index].Address))) { + UINT32 TempSize; + INT32 SubIndex; + + // + // Found overlap, split BiosModuleEntry + // Currently only support StartupAcm in 1 BiosModule. It does not support StartupAcm across 2 BiosModule or more. + // + if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) { + Error (NULL, 0, 0, "Too many Bios Module!", NULL); + return ; + } + + if (Address != gFitTableContext.BiosModule[Index].Address) { + // + // Skip the entry whose start address is same as StartupAcm + // + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = gFitTableContext.BiosModule[Index].Address; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = Address - gFitTableContext.BiosModule[Index].Address; + gFitTableContext.BiosModuleNumber ++; + gFitTableContext.FitEntryNumber++; + } + + TempSize = gFitTableContext.BiosModule[Index].Address + gFitTableContext.BiosModule[Index].Size; + gFitTableContext.BiosModule[Index].Address = Address + Size; + gFitTableContext.BiosModule[Index].Size = TempSize - gFitTableContext.BiosModule[Index].Address; + + if (gFitTableContext.BiosModule[Index].Size == 0) { + // + // remove the entry if size is 0 + // + for (SubIndex = Index; SubIndex < (INTN)gFitTableContext.BiosModuleNumber - 1; SubIndex ++) { + gFitTableContext.BiosModule[SubIndex].Address = gFitTableContext.BiosModule[SubIndex + 1].Address; + gFitTableContext.BiosModule[SubIndex].Size = gFitTableContext.BiosModule[SubIndex + 1].Size; + } + gFitTableContext.BiosModuleNumber --; + gFitTableContext.FitEntryNumber--; + } + break; + } + } +} + +UINT32 +GetFitEntryNumber ( + IN INTN argc, + IN CHAR8 **argv, + IN UINT8 *FdBuffer, + IN UINT32 FdSize + ) +/*++ + +Routine Description: + + Get FIT entry number and fill global FIT table context, from argument + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to parameter strings. + FdBuffer - FD binary buffer + FdSize - FD size + +Returns: + + FitEntryNumber - The FIT entry number + 0 - Argument parse fail + +*/ +{ + EFI_GUID Guid; + INTN Index; + UINT8 *FileBuffer; + UINT32 FileSize; + UINT32 Type; + UINT8 *MicrocodeFileBuffer; + UINT8 *MicrocodeFileBufferRaw; + UINT32 MicrocodeFileSize; + UINT32 MicrocodeBase; + UINT32 MicrocodeSize; + UINT8 *MicrocodeBuffer; + UINT32 MicrocodeRegionOffset; + UINT32 MicrocodeRegionSize; + STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + UINTN FitEntryNumber; + BOOLEAN BiosInfoExist; + BIOS_INFO_HEADER *BiosInfo; + BIOS_INFO_STRUCT *BiosInfoStruct; + UINTN BiosInfoIndex; + + // + // Init index + // + Index = 3; + if (((strcmp (argv[1], "-D") == 0) || + (strcmp (argv[1], "-d") == 0)) ) { + Index ++; + } + + // + // Fill Global Version + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-V") != 0) && + (strcmp (argv[Index], "-v") != 0)) ) { + gFitTableContext.GlobalVersion = DEFAULT_FIT_ENTRY_VERSION; + } else { + gFitTableContext.GlobalVersion = xtoi (argv[Index + 1]); + Index += 2; + } + + // + // 0. FIT Header + // + gFitTableContext.FitEntryNumber = 1; + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-F") != 0) && + (strcmp (argv[Index], "-f") != 0)) ) { + // + // Use default address + // + gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET; + } else { + // + // Get offset from parameter + // + gFitTableContext.FitTablePointerOffset = xtoi (argv[Index + 1]); + Index += 2; + } + + // + // 0.1 FIT Header 2 + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-F") != 0) && + (strcmp (argv[Index], "-f") != 0)) ) { + // + // Bypass + // + gFitTableContext.FitTablePointerOffset2 = 0; + } else { + // + // Get offset from parameter + // + gFitTableContext.FitTablePointerOffset2 = xtoi (argv[Index + 1]); + Index += 2; + } + + // + // 0.2 FIT Header version + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-V") != 0) && + (strcmp (argv[Index], "-v") != 0)) ) { + // + // Bypass + // + gFitTableContext.FitHeaderVersion = gFitTableContext.GlobalVersion; + } else { + // + // Get offset from parameter + // + gFitTableContext.FitHeaderVersion = xtoi (argv[Index + 1]); + Index += 2; + } + + // + // 0.3 Microcode alignment + // + if ((Index >= argc) || + ((strcmp (argv[Index], "-NA") != 0) && + (strcmp (argv[Index], "-na") != 0)) ) { + // + // by pass + // + gFitTableContext.MicrocodeAlignment = TRUE; + } else { + // + // no alignment + // + gFitTableContext.MicrocodeAlignment = FALSE; + Index += 1; + } + + // + // 0.4 Clear FIT table related memory + // + if ((Index >= argc) || + ((strcmp (argv[Index], "-CLEAR") != 0) && + (strcmp (argv[Index], "-clear") != 0)) ) { + // + // by pass + // + gFitTableContext.Clear = FALSE; + } else { + // + // Clear FIT table + // + gFitTableContext.Clear = TRUE; + // + // Do not parse any more + // + return 0; + } + + // + // 0.5 BiosInfo + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-I") != 0) && + (strcmp (argv[Index], "-i") != 0)) ) { + // + // Bypass + // + BiosInfoExist = FALSE; + } else { + // + // Get offset from parameter + // + BiosInfoExist = TRUE; + if (IsGuidData (argv[Index + 1], &Guid)) { + FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize); + if (FileBuffer == NULL) { + Error (NULL, 0, 0, "-I Parameter incorrect, GUID not found!", "%s", argv[Index + 1]); + // not found + return 0; + } + BiosInfo = (BIOS_INFO_HEADER *)FileBuffer; + for (BiosInfoIndex = 0; BiosInfoIndex < FileSize; BiosInfoIndex++) { + if (((BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex))->Signature == BIOS_INFO_SIGNATURE) { + BiosInfo = (BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex); + } + } + if (BiosInfo->Signature != BIOS_INFO_SIGNATURE) { + Error (NULL, 0, 0, "-I Parameter incorrect, Signature Error!", NULL); + // not found + return 0; + } + BiosInfoStruct = (BIOS_INFO_STRUCT *)(BiosInfo + 1); + + for (BiosInfoIndex = 0; BiosInfoIndex < BiosInfo->EntryCount; BiosInfoIndex++) { + if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT) != 0) { + continue; + } + switch (BiosInfoStruct[BiosInfoIndex].Type) { + case FIT_TABLE_TYPE_HEADER: + Error (NULL, 0, 0, "-I Parameter incorrect, Header Type unsupported!", NULL); + return 0; + case FIT_TABLE_TYPE_STARTUP_ACM: + if (gFitTableContext.StartupAcm.Type != 0) { + Error (NULL, 0, 0, "-I Parameter incorrect, Duplicated StartupAcm!", NULL); + return 0; + } + gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM; + gFitTableContext.StartupAcm.Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address; + gFitTableContext.StartupAcm.Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size; + gFitTableContext.StartupAcmVersion = BiosInfoStruct[BiosInfoIndex].Version; + gFitTableContext.FitEntryNumber ++; + break; + case FIT_TABLE_TYPE_BIOS_MODULE: + if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB) != 0) { + continue; + } + if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) { + Error (NULL, 0, 0, "-I Parameter incorrect, Too many Bios Module!", NULL); + return 0; + } + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size; + gFitTableContext.BiosModuleVersion = BiosInfoStruct[BiosInfoIndex].Version; + gFitTableContext.BiosModuleNumber ++; + gFitTableContext.FitEntryNumber ++; + break; + case FIT_TABLE_TYPE_MICROCODE: + if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION) == 0) { + if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) { + Error (NULL, 0, 0, "-I Parameter incorrect, Too many Microcode!", NULL); + return 0; + } + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE; + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address; + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size; + gFitTableContext.MicrocodeVersion = BiosInfoStruct[BiosInfoIndex].Version; + gFitTableContext.MicrocodeNumber++; + gFitTableContext.FitEntryNumber++; + } else { + MicrocodeRegionOffset = (UINT32)BiosInfoStruct[BiosInfoIndex].Address; + MicrocodeRegionSize = (UINT32)BiosInfoStruct[BiosInfoIndex].Size; + if (MicrocodeRegionOffset == 0) { + Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionOffset is 0", NULL); + return 0; + } + if (MicrocodeRegionSize == 0) { + Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize is 0", NULL); + return 0; + } + if (MicrocodeRegionSize > FdSize) { + Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize too large", NULL); + return 0; + } + + MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize); + MicrocodeFileSize = MicrocodeRegionSize; + MicrocodeBase = MicrocodeRegionOffset; + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer; + if (FvHeader->Signature == EFI_FVH_SIGNATURE) { + // Skip FV header + FFS header + MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER); + } else { + MicrocodeBuffer = MicrocodeFileBuffer; + } + while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) { + if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion + break; + } + if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion + break; + } + if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize + MicrocodeSize = 2048; + } else { + // + // MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment. + // + if (gFitTableContext.MicrocodeAlignment) { + MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) + MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT; + } else { + MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32)); + } + } + + // + // Add Microcode + // + if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) { + printf ("-I Parameter incorrect, Too many Microcode!\n"); + return 0; + } + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE; + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer); + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize; + gFitTableContext.MicrocodeNumber++; + gFitTableContext.FitEntryNumber++; + + MicrocodeBuffer += MicrocodeSize; + } + } + break; + case FIT_TABLE_TYPE_TPM_POLICY: + case FIT_TABLE_TYPE_BIOS_POLICY: + case FIT_TABLE_TYPE_TXT_POLICY: + case FIT_TABLE_TYPE_KEY_MANIFEST: + case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST: + case FIT_TABLE_TYPE_BIOS_DATA_AREA: + case FIT_TABLE_TYPE_CSE_SECURE_BOOT: + default : + if (BiosInfoStruct[BiosInfoIndex].Version != 0) { + if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) { + Error (NULL, 0, 0, "-I Parameter incorrect, Too many Optional Module!", NULL); + return 0; + } + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = BiosInfoStruct[BiosInfoIndex].Type; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = (UINT32)BiosInfoStruct[BiosInfoIndex].Size; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version; + gFitTableContext.OptionalModuleNumber++; + gFitTableContext.FitEntryNumber++; + } else { + if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) { + Error (NULL, 0, 0, "-I Parameter incorrect, Too many Port Module!", NULL); + return 0; + } + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = BiosInfoStruct[BiosInfoIndex].Type; + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address; + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT32)(BiosInfoStruct[BiosInfoIndex].Address >> 32); + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version; + gFitTableContext.PortModuleNumber++; + gFitTableContext.FitEntryNumber++; + } + break; + } + } + + } else { + Error (NULL, 0, 0, "-I Parameter incorrect, expect GUID!", NULL); + return 0; + } + Index += 2; + } + + // + // 1. StartupAcm + // + do { + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-S") != 0) && + (strcmp (argv[Index], "-s") != 0)) ) { + if (BiosInfoExist && (gFitTableContext.StartupAcm.Type == FIT_TABLE_TYPE_STARTUP_ACM)) { + break; + } +// Error (NULL, 0, 0, "-S Parameter incorrect, expect -S!", NULL); +// return 0; + printf ("-S not found. WARNING!\n"); + break; + } + if (IsGuidData (argv[Index + 1], &Guid)) { + FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize); + if (FileBuffer == NULL) { + Error (NULL, 0, 0, "-S Parameter incorrect, GUID not found!", "%s", argv[Index + 1]); + // not found + return 0; + } + FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize); + Index += 2; + } else { + if (Index + 2 >= argc) { + Error (NULL, 0, 0, "-S Parameter incorrect, expect Address Size!", NULL); + return 0; + } + FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]); + FileSize = xtoi (argv[Index + 2]); + Index += 3; + } + if (gFitTableContext.StartupAcm.Type != 0) { + Error (NULL, 0, 0, "-S Parameter incorrect, Duplicated StartupAcm!", NULL); + return 0; + } + gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM; + gFitTableContext.StartupAcm.Address = (UINT32) (UINTN) FileBuffer; + gFitTableContext.StartupAcm.Size = FileSize; + gFitTableContext.FitEntryNumber ++; + + // + // 1.1 StartupAcm version + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-V") != 0) && + (strcmp (argv[Index], "-v") != 0)) ) { + // + // Bypass + // + gFitTableContext.StartupAcmVersion = gFitTableContext.GlobalVersion; + } else { + // + // Get offset from parameter + // + gFitTableContext.StartupAcmVersion = xtoi (argv[Index + 1]); + Index += 2; + } + } while (FALSE); + + // + // 2. BiosModule + // + do { + if ((Index + 2 >= argc) || + ((strcmp (argv[Index], "-B") != 0) && + (strcmp (argv[Index], "-b") != 0)) ) { + if (BiosInfoExist && (gFitTableContext.BiosModuleNumber != 0)) { + break; + } +// Error (NULL, 0, 0, "-B Parameter incorrect, expect -B!", NULL); +// return 0; + printf ("-B not found. WARNING!\n"); + break; + } + + FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]); + FileSize = xtoi (argv[Index + 2]); + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize; + gFitTableContext.BiosModuleNumber ++; + gFitTableContext.FitEntryNumber ++; + + while (TRUE) { + Index += 3; + if (Index + 2 >= argc) { + break; + } + if ((strcmp (argv[Index], "-B") != 0) && + (strcmp (argv[Index], "-b") != 0) ) { + break; + } + if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) { + Error (NULL, 0, 0, "-B Parameter incorrect, Too many Bios Module!", NULL); + return 0; + } + FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]); + FileSize = xtoi (argv[Index + 2]); + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize; + gFitTableContext.BiosModuleNumber ++; + gFitTableContext.FitEntryNumber++; + } + + // + // 2.1 BiosModule version + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-V") != 0) && + (strcmp (argv[Index], "-v") != 0)) ) { + // + // Bypass + // + gFitTableContext.BiosModuleVersion = gFitTableContext.GlobalVersion; + } else { + // + // Get offset from parameter + // + gFitTableContext.BiosModuleVersion = xtoi (argv[Index + 1]); + Index += 2; + } + } while (FALSE); + + // + // 3. Microcode + // + while (TRUE) { + if (Index + 1 >= argc) { + break; + } + if ((strcmp (argv[Index], "-M") != 0) && + (strcmp (argv[Index], "-m") != 0) ) { + break; + } + if (IsGuidData (argv[Index + 2], &Guid)) { + Error (NULL, 0, 0, "-M Parameter incorrect, GUID unsupported!", NULL); + return 0; + } else { + if (Index + 2 >= argc) { + break; + } + FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]); + FileSize = xtoi (argv[Index + 2]); + Index += 3; + } + if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) { + Error (NULL, 0, 0, "-M Parameter incorrect, Too many Microcode!", NULL); + return 0; + } + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE; + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32) (UINTN) FileBuffer; + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = FileSize; + gFitTableContext.MicrocodeNumber++; + gFitTableContext.FitEntryNumber++; + } + + // + // 3.1 MicrocodeFv + // + while (TRUE) { + if (Index + 1 >= argc) { + break; + } + if ((strcmp (argv[Index], "-U") != 0) && + (strcmp (argv[Index], "-u") != 0) ) { + break; + } + // + // Get Fv + // + if (IsGuidData (argv[Index + 1], &Guid)) { + MicrocodeFileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &MicrocodeFileSize); + if (MicrocodeFileBuffer == NULL) { + Error (NULL, 0, 0, "-U Parameter incorrect, GUID not found!", "%s", argv[Index + 1]); + // not found + return 0; + } + Index += 2; + + MicrocodeBuffer = MicrocodeFileBuffer; + MicrocodeFileBufferRaw = NULL; + MicrocodeRegionOffset = MEMORY_TO_FLASH (MicrocodeFileBuffer, FdBuffer, FdSize); + MicrocodeRegionSize = 0; + MicrocodeBase = MicrocodeRegionOffset; + + } else { + if (Index + 2 >= argc) { + break; + } + Status = ReadInputFile (argv[Index + 1], &MicrocodeFileBuffer, &MicrocodeFileSize, &MicrocodeFileBufferRaw); + if (Status != STATUS_SUCCESS) { + MicrocodeRegionOffset = xtoi (argv[Index + 1]); + MicrocodeRegionSize = xtoi (argv[Index + 2]); + + if (MicrocodeRegionOffset == 0) { + Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionOffset is 0, or unable to open file", "%s", argv[Index + 1]); + return 0; + } + if (MicrocodeRegionSize == 0) { + Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize is 0", NULL); + return 0; + } + if (MicrocodeRegionSize > FdSize) { + Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize too large", NULL); + return 0; + } + + Index += 3; + + MicrocodeFileBufferRaw = NULL; + MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize); + MicrocodeFileSize = MicrocodeRegionSize; + MicrocodeBase = MicrocodeRegionOffset; + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer; + if (FvHeader->Signature == EFI_FVH_SIGNATURE) { + // Skip FV header + FFS header + MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER); + } else { + MicrocodeBuffer = MicrocodeFileBuffer; + } + } else { + MicrocodeBase = xtoi (argv[Index + 2]); + Index += 3; + MicrocodeRegionOffset = 0; + MicrocodeRegionSize = 0; + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer; + if (FvHeader->Signature == EFI_FVH_SIGNATURE) { + // Skip FV header + FFS header + MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER); + } else { + MicrocodeBuffer = MicrocodeFileBuffer; + } + } + } + while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) { + if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion + break; + } + if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion + break; + } + if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize + MicrocodeSize = 2048; + } else { + // + // MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment. + // + if (gFitTableContext.MicrocodeAlignment) { + MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) + MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT; + } else { + MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32)); + } + } + + // + // Add Microcode + // + if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) { + printf ("-U Parameter incorrect, Too many Microcode!\n"); + return 0; + } + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE; + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer); + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize; + gFitTableContext.MicrocodeNumber++; + gFitTableContext.FitEntryNumber++; + + MicrocodeBuffer += MicrocodeSize; + } + + if (MicrocodeFileBufferRaw != NULL) { + free ((VOID *)MicrocodeFileBufferRaw); + MicrocodeFileBufferRaw = NULL; + } + } + + // + // 3.3 Microcode version + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-V") != 0) && + (strcmp (argv[Index], "-v") != 0)) ) { + // + // Bypass + // + gFitTableContext.MicrocodeVersion = gFitTableContext.GlobalVersion; + } else { + // + // Get offset from parameter + // + gFitTableContext.MicrocodeVersion = xtoi (argv[Index + 1]); + Index += 2; + } + + // + // 4. Optional type + // + while (TRUE) { + if (Index + 2 >= argc) { + break; + } + if ((strcmp (argv[Index], "-O") != 0) && + (strcmp (argv[Index], "-o") != 0) ) { + break; + } + Type = xtoi (argv[Index + 1]); + // + // 1st, try GUID + // + if (IsGuidData (argv[Index + 2], &Guid)) { + FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize); + if (FileBuffer == NULL) { + Error (NULL, 0, 0, "-O Parameter incorrect, GUID not found!", "%s", argv[Index + 2]); + // not found + return 0; + } + if (FileSize >= 0x80000000) { + Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL); + return 0; + } + FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize); + Index += 3; + } else { + // + // 2nd, try file + // + Status = ReadInputFile (argv[Index + 2], &FileBuffer, &FileSize, NULL); + if (Status == STATUS_SUCCESS) { + if (FileSize >= 0x80000000) { + Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL); + free (FileBuffer); + return 0; + } + // + // Set the most significant bit + // It means the data in memory, not in flash yet. + // Assume the file size should < 2G. + // + FileSize |= 0x80000000; + Index += 3; + } else { + // + // 3rd, try + // + if (Index + 3 >= argc) { + break; + } + if ((strcmp (argv[Index + 2], "RESERVE") == 0) || + (strcmp (argv[Index + 2], "reserve") == 0)) { + FileSize = xtoi (argv[Index + 3]); + if (FileSize >= 0x80000000) { + Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL); + return 0; + } + FileBuffer = malloc (FileSize); + if (FileBuffer == NULL) { + Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL); + return 0; + } + SetMem (FileBuffer, FileSize, 0xFF); + // + // Set the most significant bit + // It means the data in memory, not in flash yet. + // Assume the file size should < 2G. + // + FileSize |= 0x80000000; + Index += 4; + } else { + // + // 4th, try + // + if (Index + 3 >= argc) { + break; + } + FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 2]); + FileSize = xtoi (argv[Index + 3]); + if (FileSize >= 0x80000000) { + Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL); + return 0; + } + Index += 4; + } + } + } + if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) { + Error (NULL, 0, 0, "-O Parameter incorrect, Too many Optional Module!", NULL); + free (FileBuffer); + return 0; + } + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = Type; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32) (UINTN) FileBuffer; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = FileSize; + + // + // 4.1 Optional Module version + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-V") != 0) && + (strcmp (argv[Index], "-v") != 0)) ) { + // + // Bypass + // + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = gFitTableContext.GlobalVersion; + } else { + // + // Get offset from parameter + // + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = xtoi (argv[Index + 1]); + Index += 2; + } + + gFitTableContext.OptionalModuleNumber ++; + gFitTableContext.FitEntryNumber++; + } + + // + // 5. Port type + // + while (TRUE) { + if (Index + 6 >= argc) { + break; + } + if ((strcmp (argv[Index], "-P") != 0) && + (strcmp (argv[Index], "-p") != 0) ) { + break; + } + + Type = xtoi (argv[Index + 1]); + if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) { + printf ("-P Parameter incorrect, Too many Port Module!\n"); + return 0; + } + + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = Type; + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT16)xtoi (argv[Index + 2]) + ((UINT16)xtoi (argv[Index + 3]) << 16); + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT8)xtoi (argv[Index + 4]) + ((UINT8)xtoi (argv[Index + 5]) << 8) + ((UINT16)xtoi (argv[Index + 6]) << 16); + Index += 7; + + // + // 5.1 Port Module version + // + if ((Index + 1 >= argc) || + ((strcmp (argv[Index], "-V") != 0) && + (strcmp (argv[Index], "-v") != 0)) ) { + // + // Bypass + // + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = 0; + } else { + // + // Get offset from parameter + // + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = xtoi (argv[Index + 1]); + Index += 2; + } + + gFitTableContext.PortModuleNumber++; + gFitTableContext.FitEntryNumber++; + } + + // + // Final: Check StartupAcm in BiosModule. + // + CheckOverlap (gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size); + FitEntryNumber = gFitTableContext.FitEntryNumber; + for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) { + if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) { + // NOTE: It might be virtual address now. Just put a place holder. + FitEntryNumber ++; + } + } + + return FitEntryNumber; +} + +VOID * +FindSpaceSkipApVector ( + IN UINT8 *FvBuffer, + IN UINT8 *Address, + IN UINTN Size + ) +/*++ + +Routine Description: + + No enough space - it might happen that it is occupied by AP wake vector. + Last chance - skip this and search again. + +Arguments: + + FvBuffer - FvRecovery binary buffer + Address - Address to be searched from + Size - Size need to be filled + +Returns: + + FitTableOffset - The FIT table offset + NULL - No enough space for FIT table + +*/ +{ + UINT8 *ApVector; + UINT8 *NewAddress; + UINTN Index; + + ApVector = (UINT8 *)((UINTN)Address & ~0xFFF); + if ((UINTN)ApVector <= (UINTN)FvBuffer) { + return NULL; + } + + NewAddress = (UINT8 *)(ApVector - Size); + for (Index = 0; Index < Size; Index ++) { + if (NewAddress[Index] != 0xFF) { + return NULL; + } + } + return NewAddress; +} + +VOID * +GetFreeSpaceFromFv ( + IN UINT8 *FvBuffer, + IN UINT32 FvSize, + IN UINT32 FitEntryNumber + ) +/*++ + +Routine Description: + + Get free space for FIT table from FvRecovery + +Arguments: + + FvBuffer - FvRecovery binary buffer + FvSize - FvRecovery size + FitEntryNumber - The FIT entry number + +Returns: + + FitTableOffset - The offset of FIT table in FvRecovery file + NULL - Free space not found + +--*/ +{ + UINT8 *FitTableOffset; + INTN Index; + INTN SubIndex; + UINT8 *OptionalModuleAddress; + EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID; + UINT32 AlignedSize; + UINT32 FitTableSize; + + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FFS_FILE_HEADER *FileHeader; + UINT64 FvLength; + UINT32 Offset; + UINT32 FileLength; + UINT32 FileOccupiedSize; + + // + // Check 4G - FitTablePointerOffset + // + if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xFFFFFFFFFFFFFFFFull) && + (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0) && + (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xEEEEEEEEEEEEEEEEull)) { + Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL); + return NULL; + } + if (gFitTableContext.FitTablePointerOffset2 != 0) { + if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xFFFFFFFFFFFFFFFFull) && + (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0) && + (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xEEEEEEEEEEEEEEEEull)) { + Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL); + return NULL; + } + } + + // + // Get EFI_FFS_VOLUME_TOP_FILE_GUID location + // + FitTableOffset = NULL; + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvBuffer; + FvLength = FvHeader->FvLength; + FileHeader = (EFI_FFS_FILE_HEADER *)(FvBuffer + FvHeader->HeaderLength); + Offset = (UINTN)FileHeader - (UINTN)FvBuffer; + + while (Offset < FvLength) { + FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF; + FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8); + if ((CompareGuid (&(FileHeader->Name), &VTFGuid)) == 0) { + // find it + FitTableOffset = (UINT8 *)FileHeader; + break; + } + FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize); + Offset = (UINTN)FileHeader - (UINTN)FvBuffer; + } + + if (FitTableOffset == NULL) { + Error (NULL, 0, 0, "EFI_FFS_VOLUME_TOP_FILE_GUID not found!", NULL); + return NULL; + } + + FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY); + FitTableSize += FIT_ALIGNMENT; + FitTableSize &= ~FIT_ALIGNMENT; + + FitTableOffset = (UINT8 *)((UINTN)FitTableOffset & ~FIT_ALIGNMENT); + FitTableOffset = (UINT8 *)(FitTableOffset - FitTableSize); + + // + // Check it + // + for (Index = 0; Index < (INTN)(FitTableSize); Index ++) { + if (FitTableOffset[Index] != 0xFF) { + // + // No enough space - it might happen that it is occupied by AP wake vector. + // Last chance - skip this and search again. + // + FitTableOffset = FindSpaceSkipApVector (FvBuffer, &FitTableOffset[Index], FitTableSize); + if (FitTableOffset == NULL) { + Error (NULL, 0, 0, "No enough space for FIT table!", NULL); + return NULL; + } + } + } + + // + // Check space for Optional module + // + OptionalModuleAddress = FitTableOffset; + for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) { + AlignedSize = gFitTableContext.OptionalModule[Index].Size; + if ((gFitTableContext.OptionalModule[Index].Size & 0x80000000) != 0) { + + // + // Need copy binary to file. + // + gFitTableContext.OptionalModule[Index].Size &= ~0x80000000; + + AlignedSize = gFitTableContext.OptionalModule[Index].Size; + if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) { + // Let it 64 byte align + AlignedSize += BIOS_MODULE_ALIGNMENT; + AlignedSize &= ~BIOS_MODULE_ALIGNMENT; + } + + OptionalModuleAddress -= AlignedSize; + + if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) { + // Let it 64 byte align + OptionalModuleAddress = (UINT8 *)((UINTN)OptionalModuleAddress & ~BIOS_MODULE_ALIGNMENT); + } + + for (SubIndex = 0; SubIndex < (INTN)(AlignedSize); SubIndex ++) { + if (OptionalModuleAddress[SubIndex] != 0xFF) { + // + // No enough space - it might happen that it is occupied by AP wake vector. + // Last chance - skip this and search again. + // + OptionalModuleAddress = FindSpaceSkipApVector (FvBuffer, &OptionalModuleAddress[SubIndex], AlignedSize); + if (OptionalModuleAddress == NULL) { + Error (NULL, 0, 0, "No enough space for OptionalModule!", NULL); + return NULL; + } + } + } + memcpy (OptionalModuleAddress, (VOID *) (UINTN) gFitTableContext.OptionalModule[Index].Address, gFitTableContext.OptionalModule[Index].Size); + free ((VOID *) (UINTN) gFitTableContext.OptionalModule[Index].Address); + gFitTableContext.OptionalModule[Index].Address = MEMORY_TO_FLASH (OptionalModuleAddress, FvBuffer, FvSize); + } + // + // Final: Check BiosPolicyData in BiosModule. + // + if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) || + (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) { + CheckOverlap (gFitTableContext.OptionalModule[Index].Address, AlignedSize); + } + } + + return FitTableOffset; +} + +VOID +PrintFitData ( + VOID + ) +/*++ + +Routine Description: + + Output FIT table information + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINT32 Index; + + printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset); + if (gFitTableContext.FitTablePointerOffset2 != 0) { + printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset2); + } + printf ("Total FIT Entry number: 0x%x\n", gFitTableContext.FitEntryNumber); + printf ("FitHeader version: 0x%04x\n", gFitTableContext.FitHeaderVersion); + if (gFitTableContext.StartupAcm.Address != 0) { + printf ("StartupAcm - (0x%08x, 0x%08x, 0x%04x)\n", gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size, gFitTableContext.StartupAcmVersion); + } + for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) { + printf ("BiosModule[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.BiosModule[Index].Address, gFitTableContext.BiosModule[Index].Size, gFitTableContext.BiosModuleVersion); + } + for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) { + printf ("Microcode[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.Microcode[Index].Address, gFitTableContext.Microcode[Index].Size, gFitTableContext.MicrocodeVersion); + } + for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) { + printf ("OptionalModule[%d] - (0x%08x, 0x%08x, 0x%02x, 0x%04x)\n", Index, gFitTableContext.OptionalModule[Index].Address, gFitTableContext.OptionalModule[Index].Size, gFitTableContext.OptionalModule[Index].Type, gFitTableContext.OptionalModule[Index].Version); + } + for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) { + printf ("PortModule[%d] - (0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%04x, 0x%02x, 0x%04x)\n", Index, + (UINT16)gFitTableContext.PortModule[Index].Address, (UINT16)(gFitTableContext.PortModule[Index].Address >> 16), + (UINT8)gFitTableContext.PortModule[Index].Size, (UINT8)(gFitTableContext.PortModule[Index].Size >> 8), (UINT16)(gFitTableContext.PortModule[Index].Size >> 16), + gFitTableContext.PortModule[Index].Type, gFitTableContext.PortModule[Index].Version); + } + + printf ("\n"); + return ; +} + +CHAR8 *mFitTypeStr[] = { + " ", + "MICROCODE ", + "STARTUP_ACM", + " ", + " ", + " ", + " ", + "BIOS_MODULE", + "TPM_POLICY ", + "BIOS_POLICY", + "TXT_POLICY ", + "KEYMANIFEST", + "BP_MANIFEST", + "BIOS_DATA_A", + " ", + " ", + "CSE_SECUREB" +}; + +CHAR8 mFitSignature[] = "'_FIT_ ' "; +CHAR8 mFitSignatureInHeader[] = "' ' "; +CHAR8 * +FitTypeToStr ( + IN FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry + ) +/*++ + +Routine Description: + + Convert FitEntry type to a string + +Arguments: + + FitEntry - Fit entry + +Returns: + + String + +--*/ +{ + if (FitEntry->Type == FIT_TABLE_TYPE_HEADER) { + CopyMem (&mFitSignatureInHeader[1], &FitEntry->Address, sizeof(FitEntry->Address)); + return mFitSignatureInHeader; + } + if (FitEntry->Type < sizeof (mFitTypeStr)/sizeof(mFitTypeStr[0])) { + return mFitTypeStr[FitEntry->Type]; + } else { + return " "; + } +} + +VOID +PrintFitTable ( + IN UINT8 *FvBuffer, + IN UINT32 FvSize + ) +/*++ + +Routine Description: + + Print Fit table in flash image + +Arguments: + + FvBuffer - FvRecovery binary buffer + FvSize - FvRecovery size + +Returns: + + None + +--*/ +{ + FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry; + UINT32 EntryNum; + UINT32 Index; + UINT32 FitTableOffset; + FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *FitEntryPort; + + printf ("##############\n"); + printf ("# FIT Table: #\n"); + printf ("##############\n"); + + printf ("FIT Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset); + FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset); + printf ("FIT Table Address: 0x%x\n", FitTableOffset); + FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize); + + // + // Check FitEntry is 16 byte aligned + // + if (((UINTN)FitEntry & 0xF) != 0) { + printf("ERROR: invalid FitEntry address 0x%X!\n", (UINT32) (UINTN) FitEntry); + return; + } + + EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF; + printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n"); + printf ("Index: Address Size Version Type C_V Checksum (Index Data Width Bit Offset)\n"); + printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n"); + for (Index = 0; Index < EntryNum; Index++) { + printf (" %02d: %016llx %06x %04x %02x-%s %02x %02x ", + Index, + (unsigned long long) FitEntry[Index].Address, + *(UINT32 *)(&FitEntry[Index].Size[0]) & 0xFFFFFF, + FitEntry[Index].Version, + FitEntry[Index].Type, + FitTypeToStr(&FitEntry[Index]), + FitEntry[Index].C_V, + FitEntry[Index].Checksum + ); + + if (Index == 0) { + if (FitEntry[Index].Type != FIT_TABLE_TYPE_HEADER) { + printf("ERROR: FIT Entry 0 is not Header Type %d!\n", FIT_TABLE_TYPE_HEADER); + return; + } + if (strcmp(mFitSignatureInHeader, mFitSignature) != 0) { + printf("ERROR: FIT Entry 0 signature invalid (%s, expected %s)!\n", mFitSignatureInHeader, mFitSignature); + return; + } + + } + + switch (FitEntry[Index].Type) { + case FIT_TABLE_TYPE_TPM_POLICY: + case FIT_TABLE_TYPE_TXT_POLICY: + if (FitEntry[Index].Version == 0) { + FitEntryPort = (FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *)&FitEntry[Index]; + printf (" ( %04x %04x %02x %02x %04x )\n", + FitEntryPort->IndexPort, + FitEntryPort->DataPort, + FitEntryPort->Width, + FitEntryPort->Bit, + FitEntryPort->Index + ); + break; + } + // Not Port Configure, pass through + default: + printf ("\n"); + break; + } + } + printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n"); + printf ("Index: Address Size Version Type C_V Checksum (Index Data Width Bit Offset)\n"); + printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n"); +} + +/** + + This function dump raw data. + + @param Data raw data + @param Size raw data size + +**/ +VOID +DumpData ( + IN UINT8 *Data, + IN UINT32 Size + ) +{ + UINT32 Index; + for (Index = 0; Index < Size; Index++) { + printf ("%02x", Data[Index]); + } +} + +/** + + This function dump raw data with colume format. + + @param Data raw data + @param Size raw data size + +**/ +VOID +DumpHex ( + IN UINT8 *Data, + IN UINT32 Size + ) +{ + UINT32 Index; + UINT32 Count; + UINT32 Left; + +#define COLUME_SIZE (16 * 2) + + Count = Size / COLUME_SIZE; + Left = Size % COLUME_SIZE; + for (Index = 0; Index < Count; Index++) { + printf ("%04x: ", Index * COLUME_SIZE); + DumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); + printf ("\n"); + } + + if (Left != 0) { + printf ("%04x: ", Index * COLUME_SIZE); + DumpData (Data + Index * COLUME_SIZE, Left); + printf ("\n"); + } +} + +// +// This table defines the ACM type string +// +CHAR8 *mAcmTypeStr[] = { + "BIOS ACM", + "SINIT ACM", +}; + +// +// This table defines the ACM capability string +// +CHAR8 *mCapabilityStr[] = { + "GETSEC[WAKEUP] for RLP ", + "MONITOR address for RLP ", + "ECX for MLE PageTable ", + "STM support ", +}; + +VOID +DumpAcm ( + IN ACM_FORMAT *Acm + ) +/*++ + +Routine Description: + + DumpAcm information + +Arguments: + + Acm - ACM buffer + +Returns: + + None + +--*/ +{ + CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable; + CHIPSET_ID_LIST *ChipsetIdList; + PROCESSOR_ID_LIST *ProcessorIdList; + UINT32 Index; + UINT8 *Buffer; + + printf ( + "*****************************************************************************\n" + "* ACM *\n" + "*****************************************************************************\n" + ); + + printf ("ACM: (%08x)\n", (UINT32) (UINTN) Acm); + printf (" ModuleType - %04x\n", Acm->ModuleType); + if (Acm->ModuleType == ACM_MODULE_TYPE_CHIPSET_ACM) { + printf (" Chipset ACM\n"); + } + printf (" ModuleSubType - %04x\n", Acm->ModuleSubType); + if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET) != 0) { + printf (" Capable of be Executed at Reset\n"); + } + if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) != 0) { + printf (" AnC Module\n"); + } + printf (" HeaderLen - %08x\n", Acm->HeaderLen); + printf (" HeaderVersion - %08x\n", Acm->HeaderVersion); + printf (" ChipsetID - %04x\n", Acm->ChipsetID); + printf (" Flags - %04x\n", Acm->Flags); + printf (" PreProduction - %04x\n", Acm->Flags & ACM_MODULE_FLAG_PREPRODUCTION); + printf (" Debug Signed - %04x\n", Acm->Flags & ACM_MODULE_FLAG_DEBUG_SIGN); + printf (" ModuleVendor - %08x\n", Acm->ModuleVendor); + printf (" Date - %08x\n", Acm->Date); + printf (" Size - %08x\n", Acm->Size); + printf (" TxtSvn - %04x\n", Acm->TxtSvn); + printf (" SeSvn - %04x\n", Acm->SeSvn); + printf (" CodeControl - %08x\n", Acm->CodeControl); + printf (" ErrorEntryPoint - %08x\n", Acm->ErrorEntryPoint); + printf (" GDTLimit - %08x\n", Acm->GDTLimit); + printf (" GDTBasePtr - %08x\n", Acm->GDTBasePtr); + printf (" SegSel - %08x\n", Acm->SegSel); + printf (" EntryPoint - %08x\n", Acm->EntryPoint); + printf (" KeySize - %08x\n", Acm->KeySize); + printf (" ScratchSize - %08x\n", Acm->ScratchSize); + + Buffer = (UINT8 *)(Acm + 1); + printf (" RSAPubKey - \n"); + DumpHex (Buffer, Acm->KeySize * 4); + printf ("\n"); + Buffer += Acm->KeySize * 4; + + if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) { + printf (" RSASig - \n"); + DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE); // PKCS #1.5 RSA Signature + printf ("\n"); + Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE; + } else { + printf (" RSAPubExp - %08x\n", *(UINT32 *)Buffer); + Buffer += 4; + + printf (" RSASig - \n"); + DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE); // PKCS #1.5 RSA Signature + printf ("\n"); + Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE; + } + Buffer += Acm->ScratchSize * 4; + + if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) { + ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer; + printf ("Chipset ACM info:\n"); + printf ( + " Guid - {%08x-%08x-%08x-%08x}\n", + ChipsetAcmInformationTable->Guid.Guid0, + ChipsetAcmInformationTable->Guid.Guid1, + ChipsetAcmInformationTable->Guid.Guid2, + ChipsetAcmInformationTable->Guid.Guid3 + ); + printf (" ChipsetACMType - %02x\n", ChipsetAcmInformationTable->ChipsetACMType); + if (ChipsetAcmInformationTable->ChipsetACMType < sizeof(mAcmTypeStr)/sizeof(mAcmTypeStr[0])) { + printf (" %s\n", mAcmTypeStr[ChipsetAcmInformationTable->ChipsetACMType]); + } + printf (" Version - %02x\n", ChipsetAcmInformationTable->Version); + printf (" Length - %04x\n", ChipsetAcmInformationTable->Length); + printf (" ChipsetIDList - %08x\n", ChipsetAcmInformationTable->ChipsetIDList); + printf (" OsSinitTableVer - %08x\n", ChipsetAcmInformationTable->OsSinitTableVer); + printf (" MinMleHeaderVer - %08x\n", ChipsetAcmInformationTable->MinMleHeaderVer); + if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) { + printf (" Capabilities - %08x\n", ChipsetAcmInformationTable->Capabilities); + for (Index = 0; Index < sizeof(mCapabilityStr)/sizeof(mCapabilityStr[0]); Index++) { + if (mCapabilityStr[Index] == NULL) { + continue; + } + printf ( + " %s- %08x\n", + mCapabilityStr[Index], + (ChipsetAcmInformationTable->Capabilities & (1 << Index)) + ); + } + printf (" AcmVersion - %02x\n", ChipsetAcmInformationTable->AcmVersion); + printf (" AcmRevision - %02x.%02x.%02x\n", ChipsetAcmInformationTable->AcmRevision[0], ChipsetAcmInformationTable->AcmRevision[1], ChipsetAcmInformationTable->AcmRevision[2]); + } + if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) { + printf (" ProcessorIDList - %08x\n", ChipsetAcmInformationTable->ProcessorIDList); + } + + ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList); + printf ("Chipset ID List info:\n"); + printf (" Count - %08x\n", ChipsetIdList->Count); + for (Index = 0; Index < ChipsetIdList->Count; Index++) { + printf (" ID[%d]:\n", Index); + printf (" Flags - %08x\n", ChipsetIdList->ChipsetID[Index].Flags); + printf (" RevisionIdMask - %08x\n", ChipsetIdList->ChipsetID[Index].Flags & ACM_CHIPSET_ID_REVISION_ID_MAKE); + printf (" VendorID - %04x\n", ChipsetIdList->ChipsetID[Index].VendorID); + printf (" DeviceID - %04x\n", ChipsetIdList->ChipsetID[Index].DeviceID); + printf (" RevisionID - %04x\n", ChipsetIdList->ChipsetID[Index].RevisionID); + } + if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) { + goto End; + } + ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList); + printf ("Processor ID List info:\n"); + printf (" Count - %08x\n", ProcessorIdList->Count); + for (Index = 0; Index < ProcessorIdList->Count; Index++) { + printf (" ID[%d]:\n", Index); + printf (" FMS - %08x\n", ProcessorIdList->ProcessorID[Index].FMS); + printf (" FMSMask - %08x\n", ProcessorIdList->ProcessorID[Index].FMSMask); + printf (" PlatformID - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformID); + printf (" PlatformMask - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformMask); + } + } + +End: + printf ( + "*****************************************************************************\n\n" + ); +} + +BOOLEAN +CheckAcm ( + IN ACM_FORMAT *Acm, + IN UINTN AcmMaxSize + ) +/*++ + +Routine Description: + + Check Acm information + +Arguments: + + Acm - ACM buffer + AcmMaxSize - ACM max size + +Returns: + + TRUE - ACM is valid + FALSE - ACM is invalid + +--*/ +{ + CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable; + CHIPSET_ID_LIST *ChipsetIdList; + PROCESSOR_ID_LIST *ProcessorIdList; + UINT8 *Buffer; + + if (Acm->ModuleType != ACM_MODULE_TYPE_CHIPSET_ACM) { + printf ("ACM invalid : ModuleType!\n"); + return FALSE; + } + if (Acm->Size * 4 > AcmMaxSize) { + printf ("ACM invalid : Size!\n"); + return FALSE; + } + + Buffer = (UINT8 *)(Acm + 1); + Buffer += Acm->KeySize * 4; + if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) { + Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE; + } else { + Buffer += 4; + Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE; + } + Buffer += Acm->ScratchSize * 4; + + if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) { + ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer; + if ((UINTN)ChipsetAcmInformationTable >= (UINTN)Acm + AcmMaxSize) { + printf ("ACM invalid : ChipsetAcmInformationTable!\n"); + return FALSE; + } + + if (CompareGuid ((EFI_GUID *)&ChipsetAcmInformationTable->Guid, (EFI_GUID *)&mChipsetAcmInformationTableGuid03) != 0) { + printf ("ACM invalid : ChipsetACMGuid!\n"); + return FALSE; + } + if (ChipsetAcmInformationTable->ChipsetACMType != CHIPSET_ACM_TYPE_BIOS) { + printf ("ACM invalid : ChipsetACMType!\n"); + return FALSE; + } + if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) { + printf ("ACM invalid : ChipsetACMVersion!\n"); + return FALSE; + } + if ((UINTN)ChipsetAcmInformationTable + ChipsetAcmInformationTable->Length > (UINTN)Acm + AcmMaxSize) { + printf ("ACM invalid : ChipsetACMLength!\n"); + return FALSE; + } + + if (ChipsetAcmInformationTable->ChipsetIDList >= AcmMaxSize) { + printf ("ACM invalid : ChipsetACMChipsetIDList!\n"); + return FALSE; + } + ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList); + if (ChipsetIdList->Count == 0) { + printf ("ACM invalid : ChipsetACMChipsetIDListCount!\n"); + return FALSE; + } + if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(CHIPSET_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_CHIPSET_ID) > AcmMaxSize) { + printf ("ACM invalid : ChipsetACMChipsetIDList!\n"); + return FALSE; + } + + if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) { + goto End; + } + + if (ChipsetAcmInformationTable->ProcessorIDList >= AcmMaxSize) { + printf ("ACM invalid : ChipsetACMProcessorIDList!\n"); + return FALSE; + } + ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList); + if (ProcessorIdList->Count == 0) { + printf ("ACM invalid : ChipsetACMProcessorIdListCount!\n"); + return FALSE; + } + if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(PROCESSOR_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_PROCESSOR_ID) > AcmMaxSize) { + printf ("ACM invalid : ChipsetACMProcessorIdList!\n"); + return FALSE; + } + } + +End: + + return TRUE; +} + +VOID +FillFitTable ( + IN UINT8 *FvBuffer, + IN UINT32 FvSize, + IN UINT8 *FitTableOffset + ) +/*++ + +Routine Description: + + Fill the FIT table information to FvRecovery + +Arguments: + + FvBuffer - FvRecovery binary buffer + FvSize - FvRecovery size + FitTableOffset - The offset of FIT table in FvRecovery file + +Returns: + + None + +--*/ +{ + FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry; + UINT32 FitIndex; + UINT32 Index; + UINT8 Checksum; + UINTN SubIndex; + FIT_TABLE_CONTEXT_ENTRY TempContextEntry; + FIRMWARE_INTERFACE_TABLE_ENTRY TempTableEntry; + + // + // 1. FitPointer + // + *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize); + if (gFitTableContext.FitTablePointerOffset2 != 0) { + *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize); + } + + FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FitTableOffset; + FitIndex = 0; + + // + // 2. FitHeader + // + FitEntry[FitIndex].Address = *(UINT64 *)"_FIT_ "; + *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.FitEntryNumber; + FitEntry[FitIndex].Version = (UINT16)gFitTableContext.FitHeaderVersion; + FitEntry[FitIndex].Type = FIT_TABLE_TYPE_HEADER; + FitEntry[FitIndex].C_V = 1; + // + // Checksum will be updated later... + // + FitEntry[FitIndex].Checksum = 0; + + // + // 3. Microcode + // + FitIndex++; + for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) { + FitEntry[FitIndex].Address = gFitTableContext.Microcode[Index].Address; + *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.Microcode[Index].Size / 16; + FitEntry[FitIndex].Version = (UINT16)gFitTableContext.MicrocodeVersion; + FitEntry[FitIndex].Type = FIT_TABLE_TYPE_MICROCODE; + FitEntry[FitIndex].C_V = 0; + FitEntry[FitIndex].Checksum = 0; + FitIndex++; + } + + // + // 4. StartupAcm + // + if (gFitTableContext.StartupAcm.Address != 0) { + FitEntry[FitIndex].Address = gFitTableContext.StartupAcm.Address; + *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.StartupAcm.Size / 16; + FitEntry[FitIndex].Version = (UINT16)gFitTableContext.StartupAcmVersion; + FitEntry[FitIndex].Type = FIT_TABLE_TYPE_STARTUP_ACM; + FitEntry[FitIndex].C_V = 0; + FitEntry[FitIndex].Checksum = 0; + FitIndex++; + } + + // + // 5. BiosModule + // + // + // BiosModule segments order needs to be put from low addresss to high for Btg requirement + // + if (gFitTableContext.BiosModuleNumber > 1) { + for (Index = 0; Index < (UINTN)gFitTableContext.BiosModuleNumber - 1; Index++){ + for (SubIndex = 0; SubIndex < gFitTableContext.BiosModuleNumber - Index - 1; SubIndex++) { + if (gFitTableContext.BiosModule[SubIndex].Address > gFitTableContext.BiosModule[SubIndex + 1].Address) { + CopyMem (&TempContextEntry, &gFitTableContext.BiosModule[SubIndex], sizeof(FIT_TABLE_CONTEXT_ENTRY)); + CopyMem (&gFitTableContext.BiosModule[SubIndex], &gFitTableContext.BiosModule[SubIndex + 1], sizeof(FIT_TABLE_CONTEXT_ENTRY)); + CopyMem (&gFitTableContext.BiosModule[SubIndex + 1], &TempContextEntry, sizeof(FIT_TABLE_CONTEXT_ENTRY)); + } + } + } + } + for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) { + FitEntry[FitIndex].Address = gFitTableContext.BiosModule[Index].Address; + *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.BiosModule[Index].Size / 16; + FitEntry[FitIndex].Version = (UINT16)gFitTableContext.BiosModuleVersion; + FitEntry[FitIndex].Type = FIT_TABLE_TYPE_BIOS_MODULE; + FitEntry[FitIndex].C_V = 0; + FitEntry[FitIndex].Checksum = 0; + FitIndex++; + } + + // + // 6. Optional module + // + for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) { + FitEntry[FitIndex].Address = gFitTableContext.OptionalModule[Index].Address; + *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.OptionalModule[Index].Size; + FitEntry[FitIndex].Version = (UINT16)gFitTableContext.OptionalModule[Index].Version; + FitEntry[FitIndex].Type = (UINT8)gFitTableContext.OptionalModule[Index].Type; + FitEntry[FitIndex].C_V = 0; + FitEntry[FitIndex].Checksum = 0; + FitIndex++; + } + + // + // 7. Port module + // + for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) { + FitEntry[FitIndex].Address = gFitTableContext.PortModule[Index].Address + ((UINT64)gFitTableContext.PortModule[Index].Size << 32); + *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; + FitEntry[FitIndex].Version = (UINT16)gFitTableContext.PortModule[Index].Version; + FitEntry[FitIndex].Type = (UINT8)gFitTableContext.PortModule[Index].Type; + FitEntry[FitIndex].C_V = 0; + FitEntry[FitIndex].Checksum = 0; + FitIndex++; + } + + // + // The FIT records must always be arranged in the ascending order of their type attribute in the FIT. + // + for (Index = 0; Index < (UINTN)FitIndex - 1; Index++){ + for (SubIndex = 0; SubIndex < FitIndex - Index - 1; SubIndex++) { + if (FitEntry[SubIndex].Type > FitEntry[SubIndex + 1].Type) { + CopyMem (&TempTableEntry, &FitEntry[SubIndex], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY)); + CopyMem (&FitEntry[SubIndex], &FitEntry[SubIndex + 1], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY)); + CopyMem (&FitEntry[SubIndex + 1], &TempTableEntry, sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY)); + } + } + } + + // + // Update FIT header signature as final step + // + Checksum = CalculateChecksum8 ((UINT8 *)&FitEntry[0], sizeof (FIRMWARE_INTERFACE_TABLE_ENTRY) * FitIndex); + FitEntry[0].Checksum = Checksum; +} + +VOID +ClearFitTable ( + IN UINT8 *FvBuffer, + IN UINT32 FvSize + ) +/*++ + +Routine Description: + + Clear the FIT table information to Fvrecovery + +Arguments: + + FvBuffer - Fvrecovery binary buffer + FvSize - Fvrecovery size + +Returns: + + None + +--*/ +{ + FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry; + UINT32 EntryNum; + UINT32 FitIndex; + UINT64 FitTablePointer; + UINT8 *Buffer; + UINT32 BufferSize; + + FitTablePointer = *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset); + FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY (FitTablePointer, FvBuffer, FvSize); + + // + // Clear FIT pointer + // + *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = 0xEEEEEEEEEEEEEEEEull; + if (gFitTableContext.FitTablePointerOffset2 != 0) { + *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = 0xEEEEEEEEEEEEEEEEull; + } + + // + // Clear FIT table + // + EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF; + for (FitIndex = 0; FitIndex < EntryNum; FitIndex++) { + switch (FitEntry[FitIndex].Type) { + case FIT_TABLE_TYPE_BIOS_POLICY: + case FIT_TABLE_TYPE_KEY_MANIFEST: + case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST: + case FIT_TABLE_TYPE_BIOS_DATA_AREA: + case FIT_TABLE_TYPE_CSE_SECURE_BOOT: + // + // Clear FIT table data buffer + // + Buffer = FLASH_TO_MEMORY (FitEntry[FitIndex].Address, FvBuffer, FvSize); + BufferSize = (*(UINT32 *)FitEntry[FitIndex].Size) & 0xFFFFFF; + SetMem (Buffer, BufferSize, 0xFF); + break; + default: + break; + } + // + // Clear FIT table itself + // + SetMem (&FitEntry[FitIndex], sizeof(FitEntry[FitIndex]), 0xFF); + } +} + +STATUS +WriteOutputFile ( + IN CHAR8 *FileName, + IN UINT8 *FileData, + IN UINT32 FileSize + ) +/*++ + +Routine Description: + + Read input file + +Arguments: + + FileName - The input file name + FileData - The input file data + FileSize - The input file size + +Returns: + + STATUS_SUCCESS - Write file data successfully + STATUS_ERROR - The file data is not written + +--*/ +{ + FILE *FpOut; + + // + // Open the output FvRecovery.fv file + // + if ((FpOut = fopen (FileName, "w+b")) == NULL) { + Error (NULL, 0, 0, "Unable to open file", "%s", FileName); + return STATUS_ERROR; + } + // + // Write the output FvRecovery.fv file + // + if ((fwrite (FileData, 1, FileSize, FpOut)) != FileSize) { + Error (NULL, 0, 0, "Write output file error!", NULL); + fclose (FpOut); + return STATUS_ERROR; + } + + // + // Close the output FvRecovery.fv file + // + fclose (FpOut); + + return STATUS_SUCCESS; +} + +UINT32 +GetFvRecoveryInfoFromFd ( + IN UINT8 *FdBuffer, + IN UINT32 FdFileSize, + OUT UINT8 **FvRecovery + ) +/*++ + +Routine Description: + + Get FvRecovery information from Fd file. + +Arguments: + + FdBuffer - Fd file buffer. + FdFileSize - Fd file size. + FvRecovery - FvRecovery pointer in Fd file buffer + +Returns: + FvRecovery file size + +--*/ +{ + UINT8 *FileBuffer = NULL; + UINT32 FvRecoveryFileSize =0; + EFI_GUID VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID; + UINT32 FvLength; + UINT32 FileLength; + + *FvRecovery = NULL; + FileBuffer = FindNextFvHeader (FdBuffer, FdFileSize); + if (FileBuffer == NULL) { + return 0; + } + + while ((UINTN)FileBuffer < (UINTN)FdBuffer + FdFileSize) { + FvLength = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->FvLength; + + if (FindFileFromFvByGuid (FileBuffer, FvLength, &VTFGuid, &FileLength) != NULL) { + // + // Found the VTF + // + FvRecoveryFileSize = FvLength; + *FvRecovery = FileBuffer; + } + + // + // Next fv + // + FileBuffer = (UINT8 *)FileBuffer + FvLength; + if ((UINTN)FileBuffer >= (UINTN)FdBuffer + FdFileSize) { + break; + } + FileBuffer = FindNextFvHeader (FileBuffer, (UINTN)FdBuffer + FdFileSize - (UINTN)FileBuffer); + if (FileBuffer == NULL) { + break; + } + + } + + // + // Return + // + return FvRecoveryFileSize; +} + +UINT32 +GetFitEntryInfo ( + IN UINT8 *FvBuffer, + IN UINT32 FvSize + ) +/*++ + +Routine Description: + + Fill the FIT table information to Fvrecovery + +Arguments: + + FvBuffer - Fvrecovery binary buffer + FvSize - Fvrecovery size + +Returns: + + 0 - Fit Table not found + +--*/ +{ + FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry; + UINT32 FitIndex; + UINT32 FitTableOffset; + + // + // 1. FitPointer + // + if (gFitTableContext.FitTablePointerOffset == 0) { + gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET; + } + gFitTableContext.FitTablePointerOffset2 = 0; + + FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset); + + FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize); + FitIndex = 0; + + // + // 2. FitHeader + // + if (FitEntry[FitIndex].Address != *(UINT64 *)"_FIT_ ") { + return 0; + } + if (FitEntry[FitIndex].Type != FIT_TABLE_TYPE_HEADER) { + return 0; + } + gFitTableContext.FitEntryNumber = *(UINT32 *)&FitEntry[FitIndex].Size[0]; + gFitTableContext.FitHeaderVersion = FitEntry[FitIndex].Version; + + // + // 3. FitEntry + // + FitIndex++; + for (; FitIndex < gFitTableContext.FitEntryNumber; FitIndex++) { + switch (FitEntry[FitIndex].Type) { + case FIT_TABLE_TYPE_MICROCODE: + gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)FitEntry[FitIndex].Address; + gFitTableContext.MicrocodeVersion = FitEntry[FitIndex].Version; + gFitTableContext.MicrocodeNumber ++; + break; + case FIT_TABLE_TYPE_STARTUP_ACM: + gFitTableContext.StartupAcm.Address = (UINT32)FitEntry[FitIndex].Address; + gFitTableContext.StartupAcmVersion = FitEntry[FitIndex].Version; + break; + case FIT_TABLE_TYPE_BIOS_MODULE: + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address; + gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = *(UINT32 *)&FitEntry[FitIndex].Size[0] * 16; + gFitTableContext.BiosModuleVersion = FitEntry[FitIndex].Version; + gFitTableContext.BiosModuleNumber ++; + break; + case FIT_TABLE_TYPE_TPM_POLICY: + case FIT_TABLE_TYPE_TXT_POLICY: + if (FitEntry[FitIndex].Version == 0) { + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address; + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT32)(FitEntry[FitIndex].Address >> 32); + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = FitEntry[FitIndex].Version; + gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = FitEntry[FitIndex].Type; + gFitTableContext.PortModuleNumber ++; + break; + } + // Not Port Configure, pass through + default: // Others + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = *(UINT32 *)&FitEntry[FitIndex].Size[0]; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = FitEntry[FitIndex].Version; + gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = FitEntry[FitIndex].Type; + gFitTableContext.OptionalModuleNumber ++; + break; + } + } + + return gFitTableContext.FitEntryNumber; +} + +STATUS +FitGen ( + IN INTN argc, + IN CHAR8 **argv + ) +/*++ + +Routine Description: + + Main function for FitGen. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + UINT32 FvRecoveryFileSize; + UINT8 *FileBuffer; + UINT8 *FileBufferRaw; + UINTN FitEntryNumber; + UINT8 *FitTableOffset; + STATUS Status; + UINT32 FitTableSize; + + BOOLEAN IsFv; + UINT8 *FdFileBuffer; + UINT32 FdFileSize; + + UINT8 *AcmBuffer; + + // + // Step 0: Check FV or FD + // + if (((strcmp (argv[1], "-D") == 0) || + (strcmp (argv[1], "-d") == 0)) ) { + IsFv = FALSE; + } else { + IsFv = TRUE; + } + + // + // Step 1: Read InputFvRecovery.fv data + // + if (IsFv) { + Status = ReadInputFile (argv[1], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw); + if (Status != STATUS_SUCCESS) { + Error (NULL, 0, 0, "Unable to open file", "%s", argv[1]); + goto exitFunc; + } + FdFileBuffer = FileBuffer; + FdFileSize = FvRecoveryFileSize; + } else { + Status = ReadInputFile (argv[2], &FdFileBuffer, &FdFileSize, &FileBufferRaw); + if (Status != STATUS_SUCCESS) { + Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]); + goto exitFunc; + } + + // + // Get Fvrecovery information + // + FvRecoveryFileSize = GetFvRecoveryInfoFromFd (FdFileBuffer, FdFileSize, &FileBuffer); + if ((FvRecoveryFileSize == 0) || (FileBuffer == NULL)) { + Error (NULL, 0, 0, "FvRecovery not found in Fd file!", NULL); + Status = STATUS_ERROR; + goto exitFunc; + } + } + + // + // Step 2: Calculate FIT entry number. + // + FitEntryNumber = GetFitEntryNumber (argc, argv, FdFileBuffer, FdFileSize); + if (!gFitTableContext.Clear) { + if (FitEntryNumber == 0) { + Status = STATUS_ERROR; + goto exitFunc; + } + + // + // For debug + // + PrintFitData (); + + // + // Add 1 more FitEntry as place holder, because we need exclude FIT table itself + // + FitEntryNumber++; + + // + // Step 3: Get enough space in FvRecovery.fv + // + FitTableOffset = GetFreeSpaceFromFv (FileBuffer, FvRecoveryFileSize, FitEntryNumber); + if (FitTableOffset == NULL) { + return STATUS_ERROR; + } + FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY); + FitTableSize += FIT_ALIGNMENT; + FitTableSize &= ~FIT_ALIGNMENT; + + CheckOverlap ( + MEMORY_TO_FLASH (FitTableOffset, FdFileBuffer, FdFileSize), + FitTableSize + ); + + // + // Get ACM buffer + // + if (gFitTableContext.StartupAcm.Address != 0) { + AcmBuffer = FLASH_TO_MEMORY(gFitTableContext.StartupAcm.Address, FdFileBuffer, FdFileSize); + if ((AcmBuffer < FdFileBuffer) || (AcmBuffer + gFitTableContext.StartupAcm.Size > FdFileBuffer + FdFileSize)) { + printf ("ACM out of range - can not validate it\n"); + AcmBuffer = NULL; + } + + if (AcmBuffer != NULL) { + if (CheckAcm ((ACM_FORMAT *)AcmBuffer, gFitTableContext.StartupAcm.Size)) { + DumpAcm ((ACM_FORMAT *)AcmBuffer); + } else { + Status = STATUS_ERROR; + goto exitFunc; + } + } + + } + + // + // Step 4: Fill the FIT table one by one + // + FillFitTable (FdFileBuffer, FdFileSize, FitTableOffset); + + // + // For debug + // + PrintFitTable (FdFileBuffer, FdFileSize); + } else { + printf ("Clear FIT table ...\n"); + // + // Step 3: Get FIT table info + // + FitEntryNumber = GetFitEntryInfo (FdFileBuffer, FdFileSize); + if (FitEntryNumber == 0) { + Error (NULL, 0, 0, "No FIT table found", NULL); + return STATUS_ERROR; + } + + // + // For debug + // + PrintFitTable (FdFileBuffer, FdFileSize); + + // + // Step 4: Clear FIT table + // + ClearFitTable (FdFileBuffer, FdFileSize); + printf ("Clear FIT table Done!\n"); + } + + // + // Step 5: Write OutputFvRecovery.fv data + // + if (IsFv) { + Status = WriteOutputFile (argv[2], FileBuffer, FvRecoveryFileSize); + } else { + Status = WriteOutputFile (argv[3], FdFileBuffer, FdFileSize); + } + +exitFunc: + if (FileBufferRaw != NULL) { + free ((VOID *)FileBufferRaw); + } + return Status; +} + +STATUS +FitView ( + IN INTN argc, + IN CHAR8 **argv + ) +/*++ + +Routine Description: + + View function for FitGen. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + UINT32 FvRecoveryFileSize; + UINT8 *FileBuffer; + UINT8 *FileBufferRaw = NULL; + STATUS Status; + + // + // Step 1: Read input file + // + Status = ReadInputFile (argv[2], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw); + if (Status != STATUS_SUCCESS) { + Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]); + goto exitFunc; + } + + // no -f option, use default FIT pointer offset + if (argc == 3) { + // + // Use default address + // + gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET; + } else if (stricmp (argv[3], "-f") == 0) { + if (argc == 5) { + // + // Get offset from parameter + // + gFitTableContext.FitTablePointerOffset = xtoi (argv[3 + 1]); + } else { + Error (NULL, 0, 0, "FIT offset not specified!", NULL); + goto exitFunc; + } + } else { + Error (NULL, 0, 0, "Invalid view option: ", "%s", argv[3]); + goto exitFunc; + } + + // + // For debug + // + PrintFitTable (FileBuffer, FvRecoveryFileSize); + +exitFunc: + if (FileBufferRaw != NULL) { + free ((VOID *)FileBufferRaw); + } + return Status; +} + +int +main ( + int argc, + char **argv + ) +/*++ + +Routine Description: + + Main function. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + SetUtilityName (UTILITY_NAME); + + // + // Display utility information + // + PrintUtilityInfo (); + + // + // Verify the correct number of arguments + // + if (argc >= MIN_VIEW_ARGS && stricmp (argv[1], "-view") == 0) { + return FitView (argc, argv); + } else if (argc >= MIN_ARGS) { + return FitGen (argc, argv); + } else { + Error (NULL, 0, 0, "invalid number of input parameters specified", NULL); + PrintUsage (); + return STATUS_ERROR; + } +} + +unsigned int +xtoi ( + char *str + ) +/*++ + +Routine Description: + + Convert hex string to uint + +Arguments: + + str - The string + +Returns: + +--*/ +{ + unsigned int u; + char c; + unsigned int m; + + if (str == NULL) { + return 0; + } + + m = (unsigned int) -1 >> 4; + // + // skip preceeding white space + // + while (*str && *str == ' ') { + str += 1; + } + // + // skip preceeding zeros + // + while (*str && *str == '0') { + str += 1; + } + // + // skip preceeding x/X character + // + if (*str && (*str == 'x' || *str == 'X')) { + str += 1; + } + // + // convert hex digits + // + u = 0; + c = *(str++); + while (c) { + if (c >= 'a' && c <= 'f') { + c -= 'a' - 'A'; + } + + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { + if (u > m) { + return (unsigned int) -1; + } + + u = (u << 4) | (c - (c >= 'A' ? 'A' - 10 : '0')); + } else { + // + // Let application exit immediately + // + Error (NULL, 0, 0, "Hex value is expected!", NULL); + exit (0); + break; + } + + c = *(str++); + } + + return u; +} + diff --git a/Silicon/Intel/Tools/FitGen/FitGen.h b/Silicon/Intel/Tools/FitGen/FitGen.h new file mode 100644 index 0000000000..9bd3f6824b --- /dev/null +++ b/Silicon/Intel/Tools/FitGen/FitGen.h @@ -0,0 +1,48 @@ +/**@file +Definitions for the FitGen utility. + +Copyright (c) 2010-2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _FIT_GEN_H +#define _FIT_GEN_H + +#include +#include +#define PI_SPECIFICATION_VERSION 0x00010000 +#define EFI_FVH_PI_REVISION EFI_FVH_REVISION +#include +#include +#include +#include +#include "EfiUtilityMsgs.c" +#include "CommonLib.h" +#include "ParseInf.h" +#include "FvLib.h" + +// +// Utility Name +// +#define UTILITY_NAME "FitGen" + +// +// Utility version information +// +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 56 +#define UTILITY_DATE __DATE__ + +// +// The minimum number of arguments accepted from the command line. +// +#define MIN_VIEW_ARGS 3 +#define MIN_ARGS 4 +#define BUF_SIZE (8 * 1024) + +#define GETOCCUPIEDSIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) +; + +#endif diff --git a/Silicon/Intel/Tools/FitGen/GNUmakefile b/Silicon/Intel/Tools/FitGen/GNUmakefile new file mode 100644 index 0000000000..00a99bb0c7 --- /dev/null +++ b/Silicon/Intel/Tools/FitGen/GNUmakefile @@ -0,0 +1,16 @@ +# @file +# GNUmakefile for building the FitGen utility. +# +# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C + +APPNAME = FitGen + +OBJECTS = FitGen.o + +include $(MAKEROOT)/Makefiles/app.makefile + +LIBS = -lCommon + diff --git a/Silicon/Intel/Tools/FitGen/Makefile b/Silicon/Intel/Tools/FitGen/Makefile new file mode 100644 index 0000000000..fd286b26be --- /dev/null +++ b/Silicon/Intel/Tools/FitGen/Makefile @@ -0,0 +1,17 @@ +# @file +# makefile for building the FitGen utility. +# +# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common + +APPNAME = FitGen + +LIBS = $(LIB_PATH)\Common.lib + +OBJECTS = FitGen.obj + +!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app + -- 2.18.0.windows.1