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