Add support for IFWI 1.7 and 2.0 layouts, improve ME parser, fix small issues spotted by static analysis

This commit is contained in:
Nikolaj Schlej 2019-08-19 11:36:02 -07:00
parent d95e533441
commit 90ff19692d
12 changed files with 1627 additions and 1138 deletions

View File

@ -12,6 +12,7 @@ SET(PROJECT_SOURCES
../common/ffs.cpp ../common/ffs.cpp
../common/nvram.cpp ../common/nvram.cpp
../common/nvramparser.cpp ../common/nvramparser.cpp
../common/meparser.cpp
../common/ffsparser.cpp ../common/ffsparser.cpp
../common/ffsreport.cpp ../common/ffsreport.cpp
../common/peimage.cpp ../common/peimage.cpp
@ -83,6 +84,6 @@ SET(PROJECT_HEADERS
../version.h ../version.h
) )
ADD_DEFINITIONS(-DU_ENABLE_NVRAM_PARSING_SUPPORT -DU_ENABLE_FIT_PARSING_SUPPORT -DU_ENABLE_GUID_DATABASE_SUPPORT) ADD_DEFINITIONS(-DU_ENABLE_NVRAM_PARSING_SUPPORT -DU_ENABLE_ME_PARSING_SUPPORT -DU_ENABLE_FIT_PARSING_SUPPORT -DU_ENABLE_GUID_DATABASE_SUPPORT)
ADD_EXECUTABLE(UEFIExtract ${PROJECT_SOURCES} ${PROJECT_HEADERS}) ADD_EXECUTABLE(UEFIExtract ${PROJECT_SOURCES} ${PROJECT_HEADERS})

View File

@ -17,35 +17,42 @@
class UEFIToolApplication : public QApplication class UEFIToolApplication : public QApplication
{ {
UEFITool tool; UEFITool* tool;
public: public:
UEFIToolApplication(int &argc, char **argv) UEFIToolApplication(int &argc, char **argv)
: QApplication(argc, argv) : QApplication(argc, argv)
{ {
setOrganizationName("LongSoft"); setOrganizationName("LongSoft");
setOrganizationDomain("longsoft.org"); setOrganizationDomain("longsoft.org");
setApplicationName("UEFITool"); setApplicationName("UEFITool NE");
tool = new UEFITool();
}
virtual ~UEFIToolApplication() {
delete tool;
}
virtual bool event(QEvent *event)
{
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
tool->openImageFile(openEvent->file());
}
return QApplication::event(event);
} }
int startup() int startup()
{ {
tool.setProgramPath(arguments().at(0)); tool->setProgramPath(arguments().at(0));
if (arguments().length() > 1) if (arguments().length() > 1)
tool.openImageFile(arguments().at(1)); tool->openImageFile(arguments().at(1));
tool.show(); tool->show();
return exec(); return exec();
} }
bool event(QEvent *event)
{
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
tool.openImageFile(openEvent->file());
}
return QApplication::event(event);
}
}; };
int main(int argc, char *argv[]) int main(int argc, char *argv[])

View File

@ -102,7 +102,7 @@ static int snapUpSize (int i) {
/* int balloc (bstring b, int len) /* int balloc (bstring b, int len)
* *
* Increase the size of the memory backing the bstring b to at least len. * Increase the size of the memory backing the bstring b to at least olen + 1.
*/ */
int balloc (bstring b, int olen) { int balloc (bstring b, int olen) {
int len; int len;
@ -124,14 +124,14 @@ int balloc (bstring b, int olen) {
reallocStrategy:; reallocStrategy:;
x = (unsigned char *) bstr__realloc (b->data, (size_t) len); x = (unsigned char *) bstr__realloc (b->data, (size_t) len + 1);
if (x == NULL) { if (x == NULL) {
/* Since we failed, try allocating the tighest possible /* Since we failed, try allocating the tighest possible
allocation */ allocation */
len = olen; len = olen;
x = (unsigned char *) bstr__realloc (b->data, (size_t) olen); x = (unsigned char *) bstr__realloc (b->data, (size_t) len + 1);
if (NULL == x) { if (NULL == x) {
return BSTR_ERR; return BSTR_ERR;
} }
@ -142,7 +142,7 @@ int balloc (bstring b, int olen) {
the extra bytes that are allocated, but not considered part of the extra bytes that are allocated, but not considered part of
the string */ the string */
if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) { if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len + 1))) {
/* Perhaps there is no available memory for the two /* Perhaps there is no available memory for the two
allocations to be in memory at once */ allocations to be in memory at once */

View File

@ -15,6 +15,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "basetypes.h" #include "basetypes.h"
#include "ustring.h" #include "ustring.h"
#include "ubytearray.h"
// Make sure we use right packing rules // Make sure we use right packing rules
#pragma pack(push,1) #pragma pack(push,1)

View File

@ -101,8 +101,7 @@ bool ustringToGuid(const UString & str, EFI_GUID & guid)
UString fileTypeToUString(const UINT8 type) UString fileTypeToUString(const UINT8 type)
{ {
switch (type) switch (type) {
{
case EFI_FV_FILETYPE_RAW: return UString("Raw"); case EFI_FV_FILETYPE_RAW: return UString("Raw");
case EFI_FV_FILETYPE_FREEFORM: return UString("Freeform"); case EFI_FV_FILETYPE_FREEFORM: return UString("Freeform");
case EFI_FV_FILETYPE_SECURITY_CORE: return UString("SEC core"); case EFI_FV_FILETYPE_SECURITY_CORE: return UString("SEC core");
@ -119,14 +118,13 @@ UString fileTypeToUString(const UINT8 type)
case EFI_FV_FILETYPE_MM_STANDALONE: return UString("MM standalone module"); case EFI_FV_FILETYPE_MM_STANDALONE: return UString("MM standalone module");
case EFI_FV_FILETYPE_MM_CORE_STANDALONE: return UString("MM standalone core"); case EFI_FV_FILETYPE_MM_CORE_STANDALONE: return UString("MM standalone core");
case EFI_FV_FILETYPE_PAD: return UString("Pad"); case EFI_FV_FILETYPE_PAD: return UString("Pad");
default: return UString("Unknown"); default: return usprintf("Unknown %u", type);
}; };
} }
UString sectionTypeToUString(const UINT8 type) UString sectionTypeToUString(const UINT8 type)
{ {
switch (type) switch (type) {
{
case EFI_SECTION_COMPRESSION: return UString("Compressed"); case EFI_SECTION_COMPRESSION: return UString("Compressed");
case EFI_SECTION_GUID_DEFINED: return UString("GUID defined"); case EFI_SECTION_GUID_DEFINED: return UString("GUID defined");
case EFI_SECTION_DISPOSABLE: return UString("Disposable"); case EFI_SECTION_DISPOSABLE: return UString("Disposable");
@ -144,7 +142,73 @@ UString sectionTypeToUString(const UINT8 type)
case EFI_SECTION_MM_DEPEX: return UString("MM dependency"); case EFI_SECTION_MM_DEPEX: return UString("MM dependency");
case INSYDE_SECTION_POSTCODE: return UString("Insyde postcode"); case INSYDE_SECTION_POSTCODE: return UString("Insyde postcode");
case PHOENIX_SECTION_POSTCODE: return UString("Phoenix postcode"); case PHOENIX_SECTION_POSTCODE: return UString("Phoenix postcode");
default: return UString("Unknown"); default: return usprintf("Unknown %u", type);
} }
} }
UString bpdtEntryTypeToUString(const UINT16 type)
{
switch (type) {
case BPDT_ENTRY_TYPE_OEM_SMIP: return UString("OEM SMIP");
case BPDT_ENTRY_TYPE_OEM_RBE: return UString("CSE RBE");
case BPDT_ENTRY_TYPE_CSE_BUP: return UString("CSE BUP");
case BPDT_ENTRY_TYPE_UCODE: return UString("uCode");
case BPDT_ENTRY_TYPE_IBB: return UString("IBB");
case BPDT_ENTRY_TYPE_SBPDT: return UString("S-BPDT");
case BPDT_ENTRY_TYPE_OBB: return UString("OBB");
case BPDT_ENTRY_TYPE_CSE_MAIN: return UString("CSE Main");
case BPDT_ENTRY_TYPE_ISH: return UString("ISH");
case BPDT_ENTRY_TYPE_CSE_IDLM: return UString("CSE IDLM");
case BPDT_ENTRY_TYPE_IFP_OVERRIDE: return UString("IFP Override");
case BPDT_ENTRY_TYPE_DEBUG_TOKENS: return UString("Debug Tokens");
case BPDT_ENTRY_TYPE_USF_PHY_CONFIG: return UString("USF Phy Config");
case BPDT_ENTRY_TYPE_USB_GPP_LUN_ID: return UString("USF GPP LUN ID");
case BPDT_ENTRY_TYPE_PMC: return UString("PMC");
case BPDT_ENTRY_TYPE_IUNIT: return UString("iUnit");
case BPDT_ENTRY_TYPE_NVM_CONFIG: return UString("NVM Config");
case BPDT_ENTRY_TYPE_UEP: return UString("UEP");
case BPDT_ENTRY_TYPE_WLAN_UCODE: return UString("WLAN uCode");
case BPDT_ENTRY_TYPE_LOCL_SPRITES: return UString("LOCL Sprites");
case BPDT_ENTRY_TYPE_OEM_KEY_MANIFEST: return UString("OEM Key Manifest");
case BPDT_ENTRY_TYPE_DEFAULTS: return UString("Defaults");
case BPDT_ENTRY_TYPE_PAVP: return UString("PAVP");
case BPDT_ENTRY_TYPE_TCSS_FW_IOM: return UString("TCSS FW IOM");
case BPDT_ENTRY_TYPE_TCSS_FW_PHY: return UString("TCSS FW PHY");
case BPDT_ENTRY_TYPE_TBT: return UString("TCSS TBT");
default: return usprintf("Unknown %u", type);
}
}
UString cpdExtensionTypeToUstring(const UINT32 type)
{
switch (type) {
case CPD_EXT_TYPE_SYSTEM_INFO: return UString("System Info");
case CPD_EXT_TYPE_INIT_SCRIPT: return UString("Init Script");
case CPD_EXT_TYPE_FEATURE_PERMISSIONS: return UString("Feature Permissions");
case CPD_EXT_TYPE_PARTITION_INFO: return UString("Partition Info");
case CPD_EXT_TYPE_SHARED_LIB_ATTRIBUTES: return UString("Shared Lib Attributes");
case CPD_EXT_TYPE_PROCESS_ATTRIBUTES: return UString("Process Attributes");
case CPD_EXT_TYPE_THREAD_ATTRIBUTES: return UString("Thread Attributes");
case CPD_EXT_TYPE_DEVICE_TYPE: return UString("Device Type");
case CPD_EXT_TYPE_MMIO_RANGE: return UString("MMIO Range");
case CPD_EXT_TYPE_SPEC_FILE_PRODUCER: return UString("Spec File Producer");
case CPD_EXT_TYPE_MODULE_ATTRIBUTES: return UString("Module Attributes");
case CPD_EXT_TYPE_LOCKED_RANGES: return UString("Locked Ranges");
case CPD_EXT_TYPE_CLIENT_SYSTEM_INFO: return UString("Client System Info");
case CPD_EXT_TYPE_USER_INFO: return UString("User Info");
case CPD_EXT_TYPE_KEY_MANIFEST: return UString("Key Manifest");
case CPD_EXT_TYPE_SIGNED_PACKAGE_INFO: return UString("Signed Package Info");
case CPD_EXT_TYPE_ANTI_CLONING_SKU_ID: return UString("Anti-cloning SKU ID");
case CPD_EXT_TYPE_CAVS: return UString("cAVS");
case CPD_EXT_TYPE_IMR_INFO: return UString("IMR Info");
case CPD_EXT_TYPE_RCIP_INFO: return UString("RCIP Info");
case CPD_EXT_TYPE_BOOT_POLICY: return UString("Boot Policy");
case CPD_EXT_TYPE_SECURE_TOKEN: return UString("Secure Token");
case CPD_EXT_TYPE_IFWI_PARTITION_MANIFEST: return UString("IFWI Partition Manifest");
case CPD_EXT_TYPE_FD_HASH: return UString("FD Hash");
case CPD_EXT_TYPE_IOM_METADATA: return UString("IOM Metadata");
case CPD_EXT_TYPE_MGP_METADATA: return UString("MGP Metadata");
case CPD_EXT_TYPE_TBT_METADATA: return UString("TBT Metadata");
default: return usprintf("Unknown %u", type);
}
}

View File

@ -26,8 +26,8 @@ extern UString guidToUString(const EFI_GUID& guid, bool convertToString = true);
extern bool ustringToGuid(const UString& str, EFI_GUID& guid); extern bool ustringToGuid(const UString& str, EFI_GUID& guid);
extern UString fileTypeToUString(const UINT8 type); extern UString fileTypeToUString(const UINT8 type);
extern UString sectionTypeToUString(const UINT8 type); extern UString sectionTypeToUString(const UINT8 type);
extern UString bpdtEntryTypeToUString(const UINT16 type);
extern UString cpdExtensionTypeToUstring(const UINT32 type);
//***************************************************************************** //*****************************************************************************
// EFI Capsule // EFI Capsule
//***************************************************************************** //*****************************************************************************
@ -586,6 +586,220 @@ typedef struct X86_RESET_VECTOR_DATA_ {
#define X86_RESET_VECTOR_DATA_UNPOPULATED 0x12345678 #define X86_RESET_VECTOR_DATA_UNPOPULATED 0x12345678
//*****************************************************************************
// IFWI
//*****************************************************************************
// BPDT
#define BPDT_GREEN_SIGNATURE 0x000055AA
#define BPDT_YELLOW_SIGNATURE 0x00AA55AA
typedef struct BPDT_HEADER_ {
UINT32 Signature;
UINT16 NumEntries;
UINT8 HeaderVersion;
UINT8 RedundancyFlag; // Reserved zero in version 1
UINT32 Checksum;
UINT32 IfwiVersion;
UINT16 FitcMajor;
UINT16 FitcMinor;
UINT16 FitcHotfix;
UINT16 FitcBuild;
} BPDT_HEADER;
#define BPDT_HEADER_VERSION_1 1
#define BPDT_HEADER_VERSION_2 2
typedef struct BPDT_ENTRY_ {
UINT32 Type : 16;
UINT32 SplitSubPartitionFirstPart : 1;
UINT32 SplitSubPartitionSecondPart : 1;
UINT32 CodeSubPartition : 1;
UINT32 UmaCachable : 1;
UINT32 Reserved: 12;
UINT32 Offset;
UINT32 Size;
} BPDT_ENTRY;
#define BPDT_ENTRY_TYPE_OEM_SMIP 0
#define BPDT_ENTRY_TYPE_OEM_RBE 1
#define BPDT_ENTRY_TYPE_CSE_BUP 2
#define BPDT_ENTRY_TYPE_UCODE 3
#define BPDT_ENTRY_TYPE_IBB 4
#define BPDT_ENTRY_TYPE_SBPDT 5
#define BPDT_ENTRY_TYPE_OBB 6
#define BPDT_ENTRY_TYPE_CSE_MAIN 7
#define BPDT_ENTRY_TYPE_ISH 8
#define BPDT_ENTRY_TYPE_CSE_IDLM 9
#define BPDT_ENTRY_TYPE_IFP_OVERRIDE 10
#define BPDT_ENTRY_TYPE_DEBUG_TOKENS 11
#define BPDT_ENTRY_TYPE_USF_PHY_CONFIG 12
#define BPDT_ENTRY_TYPE_USB_GPP_LUN_ID 13
#define BPDT_ENTRY_TYPE_PMC 14
#define BPDT_ENTRY_TYPE_IUNIT 15
#define BPDT_ENTRY_TYPE_NVM_CONFIG 16
#define BPDT_ENTRY_TYPE_UEP 17
#define BPDT_ENTRY_TYPE_WLAN_UCODE 18
#define BPDT_ENTRY_TYPE_LOCL_SPRITES 19
#define BPDT_ENTRY_TYPE_OEM_KEY_MANIFEST 20
#define BPDT_ENTRY_TYPE_DEFAULTS 21
#define BPDT_ENTRY_TYPE_PAVP 22
#define BPDT_ENTRY_TYPE_TCSS_FW_IOM 23
#define BPDT_ENTRY_TYPE_TCSS_FW_PHY 24
#define BPDT_ENTRY_TYPE_TBT 25
#define BPDT_LAST_KNOWN_ENTRY_TYPE BPDT_ENTRY_TYPE_TBT
// CPD
#define CPD_SIGNATURE 0x44504324 //$CPD
typedef struct CPD_REV1_HEADER_ {
UINT32 Signature;
UINT32 NumEntries;
UINT8 HeaderVersion; // 1
UINT8 EntryVersion;
UINT8 HeaderLength;
UINT8 HeaderChecksum;
UINT8 ShortName[4];
} CPD_REV1_HEADER;
typedef struct CPD_REV2_HEADER_ {
UINT32 Signature;
UINT32 NumEntries;
UINT8 HeaderVersion; // 2
UINT8 EntryVersion;
UINT8 HeaderLength;
UINT8 Reserved;
UINT8 ShortName[4];
UINT32 Checksum;
} CPD_REV2_HEADER;
typedef struct CPD_ENTRY_ {
UINT8 EntryName[12];
struct {
UINT32 Offset : 25;
UINT32 HuffmanCompressed : 1;
UINT32 Reserved : 6;
} Offset;
UINT32 Length;
UINT32 Reserved;
} CPD_ENTRY;
typedef struct CPD_MANIFEST_HEADER_ {
UINT32 HeaderType;
UINT32 HeaderLength;
UINT32 HeaderVersion;
UINT32 Flags;
UINT32 Vendor;
UINT32 Date;
UINT32 Size;
UINT32 HeaderId;
UINT32 Reserved1;
UINT16 VersionMajor;
UINT16 VersionMinor;
UINT16 VersionBugfix;
UINT16 VersionBuild;
UINT32 SecurityVersion;
UINT8 Reserved2[8];
UINT8 Reserved3[64];
UINT32 ModulusSize;
UINT32 ExponentSize;
//manifest_rsa_key_t public_key;
//manifest_signature_t signature;
} CPD_MANIFEST_HEADER;
typedef struct CPD_EXTENTION_HEADER_ {
UINT32 Type;
UINT32 Length;
} CPD_EXTENTION_HEADER;
#define CPD_EXT_TYPE_SYSTEM_INFO 0
#define CPD_EXT_TYPE_INIT_SCRIPT 1
#define CPD_EXT_TYPE_FEATURE_PERMISSIONS 2
#define CPD_EXT_TYPE_PARTITION_INFO 3
#define CPD_EXT_TYPE_SHARED_LIB_ATTRIBUTES 4
#define CPD_EXT_TYPE_PROCESS_ATTRIBUTES 5
#define CPD_EXT_TYPE_THREAD_ATTRIBUTES 6
#define CPD_EXT_TYPE_DEVICE_TYPE 7
#define CPD_EXT_TYPE_MMIO_RANGE 8
#define CPD_EXT_TYPE_SPEC_FILE_PRODUCER 9
#define CPD_EXT_TYPE_MODULE_ATTRIBUTES 10
#define CPD_EXT_TYPE_LOCKED_RANGES 11
#define CPD_EXT_TYPE_CLIENT_SYSTEM_INFO 12
#define CPD_EXT_TYPE_USER_INFO 13
#define CPD_EXT_TYPE_KEY_MANIFEST 14
#define CPD_EXT_TYPE_SIGNED_PACKAGE_INFO 15
#define CPD_EXT_TYPE_ANTI_CLONING_SKU_ID 16
#define CPD_EXT_TYPE_CAVS 17
#define CPD_EXT_TYPE_IMR_INFO 18
#define CPD_EXT_TYPE_BOOT_POLICY 19
#define CPD_EXT_TYPE_RCIP_INFO 20
#define CPD_EXT_TYPE_SECURE_TOKEN 21
#define CPD_EXT_TYPE_IFWI_PARTITION_MANIFEST 22
#define CPD_EXT_TYPE_FD_HASH 23
#define CPD_EXT_TYPE_IOM_METADATA 24
#define CPD_EXT_TYPE_MGP_METADATA 25
#define CPD_EXT_TYPE_TBT_METADATA 26
#define CPD_LAST_KNOWN_EXT_TYPE CPD_EXT_TYPE_TBT_METADATA
typedef struct CPD_EXT_SIGNED_PACKAGE_INFO_MODULE_ {
UINT8 Name[12];
UINT8 Type;
UINT8 HashAlgorithm;
UINT16 HashSize;
UINT32 MetadataSize;
UINT8 MetadataHash[32];
} CPD_EXT_SIGNED_PACKAGE_INFO_MODULE;
typedef struct CPD_EXT_SIGNED_PACKAGE_INFO_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 PackageName[4];
UINT32 Vcn;
UINT8 UsageBitmap[16];
UINT32 Svn;
UINT8 Reserved[16];
// EXT_SIGNED_PACKAGE_INFO_MODULE Modules[];
} CPD_EXT_SIGNED_PACKAGE_INFO;
typedef struct CPD_EXT_MODULE_ATTRIBUTES_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 CompressionType;
UINT8 Reserved[3];
UINT32 UncompressedSize;
UINT32 CompressedSize;
UINT32 GlobalModuleId;
UINT8 ImageHash[32];
} CPD_EXT_MODULE_ATTRIBUTES;
#define CPD_EXT_MODULE_COMPRESSION_TYPE_UNCOMPRESSED 0
#define CPD_EXT_MODULE_COMPRESSION_TYPE_HUFFMAN 1
#define CPD_EXT_MODULE_COMPRESSION_TYPE_LZMA 2
typedef struct CPD_EXT_IFWI_PARTITION_MANIFEST_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 PartitionName[4];
UINT32 CompletePartitionLength;
UINT16 PartitionVersionMinor;
UINT16 PartitionVersionMajor;
UINT32 DataFormatVersion;
UINT32 InstanceId;
UINT32 SupportMultipleInstances : 1;
UINT32 SupportApiVersionBasedUpdate : 1;
UINT32 ActionOnUpdate : 2;
UINT32 ObeyFullUpdateRules : 1;
UINT32 IfrEnableOnly : 1;
UINT32 AllowCrossPointUpdate : 1;
UINT32 AllowCrossHotfixUpdate : 1;
UINT32 PartialUpdateOnly : 1;
UINT32 ReservedFlags : 23;
UINT32 HashAlgorithm : 8;
UINT32 HashSize : 24;
UINT8 CompletePartitionHash[32];
UINT8 Reserved[20];
} CPD_EXT_IFWI_PARTITION_MANIFEST;
// Restore previous packing rules // Restore previous packing rules
#pragma pack(pop) #pragma pack(pop)

View File

@ -39,13 +39,14 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
namespace Qt { namespace Qt {
enum GlobalColor { enum GlobalColor {
red = 7, red = 7,
green = 8,
cyan = 10, cyan = 10,
yellow = 12, yellow = 12,
}; };
} }
#endif #endif
// Region info structure definition // Region info
struct REGION_INFO { struct REGION_INFO {
UINT32 offset; UINT32 offset;
UINT32 length; UINT32 length;
@ -54,12 +55,28 @@ struct REGION_INFO {
friend bool operator< (const REGION_INFO & lhs, const REGION_INFO & rhs){ return lhs.offset < rhs.offset; } friend bool operator< (const REGION_INFO & lhs, const REGION_INFO & rhs){ return lhs.offset < rhs.offset; }
}; };
// BPDT partition info
struct BPDT_PARTITION_INFO {
BPDT_ENTRY ptEntry;
UINT8 type;
UModelIndex index;
friend bool operator< (const BPDT_PARTITION_INFO & lhs, const BPDT_PARTITION_INFO & rhs){ return lhs.ptEntry.Offset < rhs.ptEntry.Offset; }
};
// CPD partition info
struct CPD_PARTITION_INFO {
CPD_ENTRY ptEntry;
UINT8 type;
UModelIndex index;
friend bool operator< (const CPD_PARTITION_INFO & lhs, const CPD_PARTITION_INFO & rhs){ return lhs.ptEntry.Offset.Offset < rhs.ptEntry.Offset.Offset; }
};
// Constructor // Constructor
FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel), FfsParser::FfsParser(TreeModel* treeModel) : model(treeModel),
imageBase(0), addressDiff(0x100000000ULL), imageBase(0), addressDiff(0x100000000ULL),
bgAcmFound(false), bgKeyManifestFound(false), bgBootPolicyFound(false), bgProtectedRegionsBase(0) { bgAcmFound(false), bgKeyManifestFound(false), bgBootPolicyFound(false), bgProtectedRegionsBase(0) {
nvramParser = new NvramParser(treeModel, this); nvramParser = new NvramParser(treeModel, this);
meParser = new MeParser(treeModel); meParser = new MeParser(treeModel, this);
} }
// Destructor // Destructor
@ -900,6 +917,23 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
msg(usprintf("%s: microcode header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index); msg(usprintf("%s: microcode header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
} }
} }
else if (itemType == Types::BpdtStore) {
UByteArray bpdtStore = data.mid(itemOffset, itemSize);
// Get info
name = UString("BPDT region");
info = usprintf("Full size: %Xh (%u)", bpdtStore.size(), bpdtStore.size());
// Add tree item
UModelIndex bpdtIndex = model->addItem(headerSize + itemOffset, Types::BpdtStore, 0, name, UString(), info, UByteArray(), bpdtStore, UByteArray(), Fixed, index);
// Parse BPDT region
UModelIndex bpdtPtIndex;
result = parseBpdtRegion(bpdtStore, 0, 0, bpdtIndex, bpdtPtIndex);
if (result) {
msg(usprintf("%s: BPDT store parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
}
}
else { else {
return U_UNKNOWN_ITEM_TYPE; return U_UNKNOWN_ITEM_TYPE;
} }
@ -937,6 +971,12 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
case Types::Microcode: case Types::Microcode:
// Parsing already done // Parsing already done
break; break;
case Types::BpdtStore:
// Parsing already done
break;
case Types::BpdtPartition:
// Parsing already done
break;
case Types::Padding: case Types::Padding:
// No parsing required // No parsing required
break; break;
@ -1226,6 +1266,48 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l
nextItemOffset = offset - EFI_FV_SIGNATURE_OFFSET; nextItemOffset = offset - EFI_FV_SIGNATURE_OFFSET;
break; break;
} }
else if (readUnaligned(currentPos) == BPDT_GREEN_SIGNATURE || readUnaligned(currentPos) == BPDT_YELLOW_SIGNATURE) {
// Check data size
if (restSize < sizeof(BPDT_HEADER))
continue;
const BPDT_HEADER *bpdtHeader = (const BPDT_HEADER *)currentPos;
// Check version
if (bpdtHeader->HeaderVersion != BPDT_HEADER_VERSION_1) // IFWI 2.0 only for now
continue;
UINT32 ptBodySize = bpdtHeader->NumEntries * sizeof(BPDT_ENTRY);
UINT32 ptSize = sizeof(BPDT_HEADER) + ptBodySize;
// Check data size again
if (restSize < ptSize)
continue;
UINT32 sizeCandidate = 0;
// Parse partition table
const BPDT_ENTRY* firstPtEntry = (const BPDT_ENTRY*)((const UINT8*)bpdtHeader + sizeof(BPDT_HEADER));
for (UINT16 i = 0; i < bpdtHeader->NumEntries; i++) {
// Populate entry header
const BPDT_ENTRY* ptEntry = firstPtEntry + i;
// Check that entry is present in the image
if (ptEntry->Offset != 0
&& ptEntry->Offset != 0xFFFFFFFF
&& ptEntry->Size != 0
&& sizeCandidate < ptEntry->Offset + ptEntry->Size) {
sizeCandidate = ptEntry->Offset + ptEntry->Size;
}
}
// Check size candidate
if (sizeCandidate == 0)
continue;
// All checks passed, BPDT found
nextItemType = Types::BpdtStore;
nextItemSize = sizeCandidate;
nextItemAlternativeSize = sizeCandidate;
nextItemOffset = offset;
break;
}
} }
// No more stores found // No more stores found
@ -1294,7 +1376,7 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
UINT32 fileSize = getFileSize(volumeBody, fileOffset, ffsVersion); UINT32 fileSize = getFileSize(volumeBody, fileOffset, ffsVersion);
// Check that we are at the empty space // Check that we are at the empty space
UByteArray header = volumeBody.mid(fileOffset, std::min(sizeof(EFI_FFS_FILE_HEADER), (size_t)volumeBodySize - fileOffset)); UByteArray header = volumeBody.mid(fileOffset, (int)std::min(sizeof(EFI_FFS_FILE_HEADER), (size_t)volumeBodySize - fileOffset));
if (header.count(emptyByte) == header.size()) { //Empty space if (header.count(emptyByte) == header.size()) { //Empty space
// Check volume usedSpace entry to be valid // Check volume usedSpace entry to be valid
if (usedSpace > 0 && usedSpace == fileOffset + volumeHeaderSize) { if (usedSpace > 0 && usedSpace == fileOffset + volumeHeaderSize) {
@ -3316,7 +3398,12 @@ USTATUS FfsParser::markProtectedRangeRecursive(const UModelIndex & index, const
if (std::min(currentOffset + currentSize, range.Offset + range.Size) > std::max(currentOffset, range.Offset)) { if (std::min(currentOffset + currentSize, range.Offset + range.Size) > std::max(currentOffset, range.Offset)) {
if (range.Offset <= currentOffset && currentOffset + currentSize <= range.Offset + range.Size) { // Mark as fully in range if (range.Offset <= currentOffset && currentOffset + currentSize <= range.Offset + range.Size) { // Mark as fully in range
model->setMarking(index, range.Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB ? Qt::red : Qt::cyan); if (range.Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB) {
model->setMarking(index, Qt::red);
}
else {
model->setMarking(index, Qt::cyan);
}
} }
else { // Mark as partially in range else { // Mark as partially in range
model->setMarking(index, Qt::yellow); model->setMarking(index, Qt::yellow);
@ -4251,3 +4338,746 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const
// No need to parse the body further for now // No need to parse the body further for now
return U_SUCCESS; return U_SUCCESS;
} }
USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 localOffset, const UINT32 sbpdtOffsetFixup, const UModelIndex & parent, UModelIndex & index)
{
UINT32 regionSize = (UINT32)region.size();
// Check region size
if (regionSize < sizeof(BPDT_HEADER)) {
msg(usprintf("%s: BPDT region too small to fit BPDT partition table header", __FUNCTION__), parent);
return U_INVALID_ME_PARTITION_TABLE;
}
// Populate partition table header
const BPDT_HEADER* ptHeader = (const BPDT_HEADER*)(region.constData());
// Check region size again
UINT32 ptBodySize = ptHeader->NumEntries * sizeof(BPDT_ENTRY);
UINT32 ptSize = sizeof(BPDT_HEADER) + ptBodySize;
if (regionSize < ptSize) {
msg(usprintf("%s: BPDT region too small to fit BPDT partition table", __FUNCTION__), parent);
return U_INVALID_ME_PARTITION_TABLE;
}
// Get info
UByteArray header = region.left(sizeof(BPDT_HEADER));
UByteArray body = region.mid(sizeof(BPDT_HEADER), ptBodySize);
UString name = UString("BPDT partition table");
UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u\nVersion: %2Xh\n"
"IFWI version: %Xh\nFITC version: %u.%u.%u.%u",
ptSize, ptSize,
header.size(), header.size(),
ptBodySize, ptBodySize,
ptHeader->NumEntries,
ptHeader->HeaderVersion,
ptHeader->IfwiVersion,
ptHeader->FitcMajor, ptHeader->FitcMinor, ptHeader->FitcHotfix, ptHeader->FitcBuild);
// Add tree item
index = model->addItem(localOffset, Types::BpdtStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
// Adjust offset
UINT32 offset = sizeof(BPDT_HEADER);
// Add partition table entries
std::vector<BPDT_PARTITION_INFO> partitions;
const BPDT_ENTRY* firstPtEntry = (const BPDT_ENTRY*)((const UINT8*)ptHeader + sizeof(BPDT_HEADER));
for (UINT16 i = 0; i < ptHeader->NumEntries; i++) {
// Populate entry header
const BPDT_ENTRY* ptEntry = firstPtEntry + i;
// Get info
name = bpdtEntryTypeToUString(ptEntry->Type);
info = usprintf("Full size: %Xh (%u)\nType: %Xh\nPartition offset: %Xh\nPartition length: %Xh",
sizeof(BPDT_ENTRY), sizeof(BPDT_ENTRY),
ptEntry->Type,
ptEntry->Offset,
ptEntry->Size) +
UString("\nSplit sub-partition first part: ") + (ptEntry->SplitSubPartitionFirstPart ? "Yes" : "No") +
UString("\nSplit sub-partition second part: ") + (ptEntry->SplitSubPartitionSecondPart ? "Yes" : "No") +
UString("\nCode sub-partition: ") + (ptEntry->CodeSubPartition ? "Yes" : "No") +
UString("\nUMA cachable: ") + (ptEntry->UmaCachable ? "Yes" : "No");
// Add tree item
UModelIndex entryIndex = model->addItem(localOffset + offset, Types::BpdtEntry, 0, name, UString(), info, UByteArray(), UByteArray((const char*)ptEntry, sizeof(BPDT_ENTRY)), UByteArray(), Fixed, index);
// Adjust offset
offset += sizeof(BPDT_ENTRY);
if (ptEntry->Offset != 0 && ptEntry->Offset != 0xFFFFFFFF && ptEntry->Size != 0) {
// Add to partitions vector
BPDT_PARTITION_INFO partition;
partition.type = Types::BpdtPartition;
partition.ptEntry = *ptEntry;
partition.ptEntry.Offset -= sbpdtOffsetFixup;
partition.index = entryIndex;
partitions.push_back(partition);
}
}
// Add padding if there's no partions to add
if (partitions.size() == 0) {
UByteArray partition = region.mid(ptSize);
// Get info
name = UString("Padding");
info = usprintf("Full size: %Xh (%u)",
partition.size(), partition.size());
// Add tree item
model->addItem(localOffset + ptSize, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
make_partition_table_consistent:
// Sort partitions by offset
std::sort(partitions.begin(), partitions.end());
// Check for intersections and paddings between partitions
BPDT_PARTITION_INFO padding;
// Check intersection with the partition table header
if (partitions.front().ptEntry.Offset < ptSize) {
msg(usprintf("%s: BPDT partition has intersection with BPDT partition table, skipped", __FUNCTION__),
partitions.front().index);
partitions.erase(partitions.begin());
goto make_partition_table_consistent;
}
// Check for padding between partition table and the first partition
else if (partitions.front().ptEntry.Offset > ptSize) {
padding.ptEntry.Offset = ptSize;
padding.ptEntry.Size = partitions.front().ptEntry.Offset - padding.ptEntry.Offset;
padding.type = Types::Padding;
partitions.insert(partitions.begin(), padding);
}
// Check for intersections/paddings between partitions
for (size_t i = 1; i < partitions.size(); i++) {
UINT32 previousPartitionEnd = partitions[i - 1].ptEntry.Offset + partitions[i - 1].ptEntry.Size;
// Check that partition is fully present in the image
if ((UINT64)partitions[i].ptEntry.Offset + (UINT64)partitions[i].ptEntry.Size > regionSize) {
if ((UINT64)partitions[i].ptEntry.Offset >= (UINT64)region.size()) {
msg(usprintf("%s: BPDT partition is located outside of the opened image, skipped", __FUNCTION__), partitions[i].index);
partitions.erase(partitions.begin() + i);
goto make_partition_table_consistent;
}
else {
msg(usprintf("%s: BPDT partition can't fit into it's region, truncated", __FUNCTION__), partitions[i].index);
partitions[i].ptEntry.Size = regionSize - (UINT32)partitions[i].ptEntry.Offset;
}
}
// Check for intersection with previous partition
if (partitions[i].ptEntry.Offset < previousPartitionEnd) {
// Check if current partition is located inside previous one
if (partitions[i].ptEntry.Offset + partitions[i].ptEntry.Size <= previousPartitionEnd) {
msg(usprintf("%s: BPDT partition is located inside another BPDT partition, skipped", __FUNCTION__),
partitions[i].index);
partitions.erase(partitions.begin() + i);
goto make_partition_table_consistent;
}
else {
msg(usprintf("%s: BPDT partition intersects with prevous one, skipped", __FUNCTION__),
partitions[i].index);
partitions.erase(partitions.begin() + i);
goto make_partition_table_consistent;
}
}
// Check for padding between current and previous partitions
else if (partitions[i].ptEntry.Offset > previousPartitionEnd) {
padding.ptEntry.Offset = previousPartitionEnd;
padding.ptEntry.Size = partitions[i].ptEntry.Offset - previousPartitionEnd;
padding.type = Types::Padding;
std::vector<BPDT_PARTITION_INFO>::iterator iter = partitions.begin();
std::advance(iter, i);
partitions.insert(iter, padding);
}
}
// Partition map is consistent
for (size_t i = 0; i < partitions.size(); i++) {
if (partitions[i].type == Types::BpdtPartition) {
// Get info
UString name = bpdtEntryTypeToUString(partitions[i].ptEntry.Type);
UByteArray partition = region.mid(partitions[i].ptEntry.Offset, partitions[i].ptEntry.Size);
UByteArray signature = partition.left(sizeof(UINT32));
UString info = usprintf("Full size: %Xh (%u)\nType: %Xh",
partition.size(), partition.size(),
partitions[i].ptEntry.Type) +
UString("\nSplit sub-partition first part: ") + (partitions[i].ptEntry.SplitSubPartitionFirstPart ? "Yes" : "No") +
UString("\nSplit sub-partition second part: ") + (partitions[i].ptEntry.SplitSubPartitionSecondPart ? "Yes" : "No") +
UString("\nCode sub-partition: ") + (partitions[i].ptEntry.CodeSubPartition ? "Yes" : "No") +
UString("\nUMA cachable: ") + (partitions[i].ptEntry.UmaCachable ? "Yes" : "No");
UString text = bpdtEntryTypeToUString(partitions[i].ptEntry.Type);
// Add tree item
UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset, Types::BpdtPartition, 0, name, text, info, UByteArray(), partition, UByteArray(), Fixed, parent);
// Special case of S-BPDT
if (partitions[i].ptEntry.Type == BPDT_ENTRY_TYPE_SBPDT) {
UModelIndex sbpdtIndex;
parseBpdtRegion(partition, 0, partitions[i].ptEntry.Offset, partitionIndex, sbpdtIndex); // Third parameter is a fixup for S-BPDT offset entries, because they are calculated from the start of BIOS region
}
// Parse code partitions
if (readUnaligned((const UINT32*)partition.constData()) == CPD_SIGNATURE) {
// Parse code partition contents
UModelIndex cpdIndex;
parseCpdRegion(partition, localOffset, partitionIndex, cpdIndex);
}
if (partitions[i].ptEntry.Type > BPDT_LAST_KNOWN_ENTRY_TYPE) {
msg(usprintf("%s: BPDT entry of unknown type found", __FUNCTION__), partitionIndex);
}
}
else if (partitions[i].type == Types::Padding) {
UByteArray partition = region.mid(partitions[i].ptEntry.Offset, partitions[i].ptEntry.Size);
// Get info
name = UString("Padding");
info = usprintf("Full size: %Xh (%u)",
partition.size(), partition.size());
// Add tree item
model->addItem(localOffset + partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
}
}
// Add padding after the last region
if ((UINT64)partitions.back().ptEntry.Offset + (UINT64)partitions.back().ptEntry.Size < regionSize) {
UByteArray partition = region.mid(partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size, regionSize - padding.ptEntry.Offset);
// Get info
name = UString("Padding");
info = usprintf("Full size: %Xh (%u)",
partition.size(), partition.size());
// Add tree item
model->addItem(localOffset + partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
}
return U_SUCCESS;
}
USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
{
// Check directory size
if ((UINT32)region.size() < sizeof(CPD_REV1_HEADER)) {
msg(usprintf("%s: CPD too small to fit rev1 partition table header", __FUNCTION__), parent);
return U_INVALID_ME_PARTITION_TABLE;
}
// Populate partition table header
const CPD_REV1_HEADER* cpdHeader = (const CPD_REV1_HEADER*)region.constData();
// Check header version to be known
UINT32 ptHeaderSize = 0;
if (cpdHeader->HeaderVersion == 2) {
if ((UINT32)region.size() < sizeof(CPD_REV2_HEADER)) {
msg(usprintf("%s: CPD too small to fit rev2 partition table header", __FUNCTION__), parent);
return U_INVALID_ME_PARTITION_TABLE;
}
ptHeaderSize = sizeof(CPD_REV2_HEADER);
}
else if (cpdHeader->HeaderVersion == 1) {
ptHeaderSize = sizeof(CPD_REV1_HEADER);
}
// Check directory size again
UINT32 ptBodySize = cpdHeader->NumEntries * sizeof(CPD_ENTRY);
UINT32 ptSize = ptHeaderSize + ptBodySize;
if ((UINT32)region.size() < ptSize) {
msg(usprintf("%s: CPD too small to fit the whole partition table", __FUNCTION__), parent);
return U_INVALID_ME_PARTITION_TABLE;
}
// Get info
UByteArray header = region.left(ptHeaderSize);
UByteArray body = region.mid(ptHeaderSize);
UString name = usprintf("CPD partition table");
UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u\n"
"Header version: %02X\nEntry version: %02X",
region.size(), region.size(),
header.size(), header.size(),
body.size(), body.size(),
cpdHeader->NumEntries,
cpdHeader->HeaderVersion,
cpdHeader->EntryVersion);
// Add tree item
index = model->addItem(localOffset, Types::CpdStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
// Add partition table entries
std::vector<CPD_PARTITION_INFO> partitions;
UINT32 offset = ptHeaderSize;
const CPD_ENTRY* firstCpdEntry = (const CPD_ENTRY*)(body.constData());
for (UINT32 i = 0; i < cpdHeader->NumEntries; i++) {
// Populate entry header
const CPD_ENTRY* cpdEntry = firstCpdEntry + i;
UByteArray entry((const char*)cpdEntry, sizeof(CPD_ENTRY));
// Get info
name = usprintf("%c%c%c%c%c%c%c%c%c%c%c%c",
cpdEntry->EntryName[0], cpdEntry->EntryName[1], cpdEntry->EntryName[2], cpdEntry->EntryName[3],
cpdEntry->EntryName[4], cpdEntry->EntryName[5], cpdEntry->EntryName[6], cpdEntry->EntryName[7],
cpdEntry->EntryName[8], cpdEntry->EntryName[9], cpdEntry->EntryName[10], cpdEntry->EntryName[11]);
info = usprintf("Full size: %Xh (%u)\nEntry offset: %Xh\nEntry length: %Xh\nHuffman compressed: ",
entry.size(), entry.size(),
cpdEntry->Offset.Offset,
cpdEntry->Length)
+ (cpdEntry->Offset.HuffmanCompressed ? "Yes" : "No");
// Add tree item
UModelIndex entryIndex = model->addItem(offset, Types::CpdEntry, 0, name, UString(), info, UByteArray(), entry, UByteArray(), Fixed, index);
// Adjust offset
offset += sizeof(CPD_ENTRY);
if (cpdEntry->Offset.Offset != 0 && cpdEntry->Length != 0) {
// Add to partitions vector
CPD_PARTITION_INFO partition;
partition.type = Types::CpdPartition;
partition.ptEntry = *cpdEntry;
partition.index = entryIndex;
partitions.push_back(partition);
}
}
// Add padding if there's no partions to add
if (partitions.size() == 0) {
UByteArray partition = region.mid(ptSize);
// Get info
name = UString("Padding");
info = usprintf("Full size: %Xh (%u)",
partition.size(), partition.size());
// Add tree item
model->addItem(localOffset + ptSize, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
return U_SUCCESS;
}
// Sort partitions by offset
std::sort(partitions.begin(), partitions.end());
// Because lenghts for all Huffmann-compressed partitions mean nothing at all, we need to split all partitions into 2 classes:
// 1. CPD manifest (should be the first)
// 2. Metadata entries (should begin right after partition manifest and end before any code partition)
UINT32 i = 1;
while (i < partitions.size()) {
name = usprintf("%c%c%c%c%c%c%c%c%c%c%c%c",
partitions[i].ptEntry.EntryName[0], partitions[i].ptEntry.EntryName[1], partitions[i].ptEntry.EntryName[2], partitions[i].ptEntry.EntryName[3],
partitions[i].ptEntry.EntryName[4], partitions[i].ptEntry.EntryName[5], partitions[i].ptEntry.EntryName[6], partitions[i].ptEntry.EntryName[7],
partitions[i].ptEntry.EntryName[8], partitions[i].ptEntry.EntryName[9], partitions[i].ptEntry.EntryName[10], partitions[i].ptEntry.EntryName[11]);
// Check if the current entry is metadata entry
if (!name.contains(".met")) {
// No need to parse further, all metadata partitions are parsed
break;
}
// Parse into data block, find Module Attributes extension, and get compressed size from there
UINT32 offset = 0;
UINT32 length = 0xFFFFFFFF; // Special guardian value
UByteArray partition = region.mid(partitions[i].ptEntry.Offset.Offset, partitions[i].ptEntry.Length);
while (offset < (UINT32)partition.size()) {
const CPD_EXTENTION_HEADER* extHeader = (const CPD_EXTENTION_HEADER*) (partition.constData() + offset);
if (extHeader->Length <= ((UINT32)partition.size() - offset)) {
if (extHeader->Type == CPD_EXT_TYPE_MODULE_ATTRIBUTES) {
const CPD_EXT_MODULE_ATTRIBUTES* attrHeader = (const CPD_EXT_MODULE_ATTRIBUTES*)(partition.constData() + offset);
length = attrHeader->CompressedSize;
}
offset += extHeader->Length;
}
else break;
}
// Search down for corresponding code partition
// Construct it's name by replacing last 4 non-zero butes of the name with zeros
UINT32 j = 0;
for (UINT32 k = 11; k > 0 && j < 4; k--) {
if (name[k] != '\x00') {
name[k] = '\x00';
j++;
}
}
// Search
j = i + 1;
while (j < partitions.size()) {
if (name == usprintf("%c%c%c%c%c%c%c%c%c%c%c%c",
partitions[j].ptEntry.EntryName[0], partitions[j].ptEntry.EntryName[1], partitions[j].ptEntry.EntryName[2], partitions[j].ptEntry.EntryName[3],
partitions[j].ptEntry.EntryName[4], partitions[j].ptEntry.EntryName[5], partitions[j].ptEntry.EntryName[6], partitions[j].ptEntry.EntryName[7],
partitions[j].ptEntry.EntryName[8], partitions[j].ptEntry.EntryName[9], partitions[j].ptEntry.EntryName[10], partitions[j].ptEntry.EntryName[11])) {
// Found it, update it's Length if needed
if (partitions[j].ptEntry.Offset.HuffmanCompressed) {
partitions[j].ptEntry.Length = length;
}
else if (length != 0xFFFFFFFF && partitions[j].ptEntry.Length != length) {
msg(usprintf("%s: partition size mismatch between partition table (%Xh) and partition metadata (%Xh)", __FUNCTION__,
partitions[j].ptEntry.Length, length), partitions[j].index);
partitions[j].ptEntry.Length = length; // Believe metadata
}
// No need to search further
break;
}
// Check the next partition
j++;
}
// Check the next partition
i++;
}
make_partition_table_consistent:
// Sort partitions by offset
std::sort(partitions.begin(), partitions.end());
// Check for intersections and paddings between partitions
CPD_PARTITION_INFO padding;
// Check intersection with the partition table header
if (partitions.front().ptEntry.Offset.Offset < ptSize) {
msg(usprintf("%s: CPD partition has intersection with CPD partition table, skipped", __FUNCTION__),
partitions.front().index);
partitions.erase(partitions.begin());
goto make_partition_table_consistent;
}
// Check for padding between partition table and the first partition
else if (partitions.front().ptEntry.Offset.Offset > ptSize) {
padding.ptEntry.Offset.Offset = ptSize;
padding.ptEntry.Length = partitions.front().ptEntry.Offset.Offset - padding.ptEntry.Offset.Offset;
padding.type = Types::Padding;
partitions.insert(partitions.begin(), padding);
}
// Check for intersections/paddings between partitions
for (size_t i = 1; i < partitions.size(); i++) {
UINT32 previousPartitionEnd = partitions[i - 1].ptEntry.Offset.Offset + partitions[i - 1].ptEntry.Length;
// Check that current region is fully present in the image
if ((UINT64)partitions[i].ptEntry.Offset.Offset + (UINT64)partitions[i].ptEntry.Length > (UINT64)region.size()) {
if ((UINT64)partitions[i].ptEntry.Offset.Offset >= (UINT64)region.size()) {
msg(usprintf("%s: CPD partition is located outside of the opened image, skipped", __FUNCTION__), partitions[i].index);
partitions.erase(partitions.begin() + i);
goto make_partition_table_consistent;
}
else {
msg(usprintf("%s: CPD partition can't fit into it's region, truncated", __FUNCTION__), partitions[i].index);
partitions[i].ptEntry.Length = (UINT32)region.size() - (UINT32)partitions[i].ptEntry.Offset.Offset;
}
}
// Check for intersection with previous partition
if (partitions[i].ptEntry.Offset.Offset < previousPartitionEnd) {
// Check if current partition is located inside previous one
if (partitions[i].ptEntry.Offset.Offset + partitions[i].ptEntry.Length <= previousPartitionEnd) {
msg(usprintf("%s: CPD partition is located inside another CPD partition, skipped", __FUNCTION__),
partitions[i].index);
partitions.erase(partitions.begin() + i);
goto make_partition_table_consistent;
}
else {
msg(usprintf("%s: CPD partition intersects with previous one, skipped", __FUNCTION__),
partitions[i].index);
partitions.erase(partitions.begin() + i);
goto make_partition_table_consistent;
}
}
// Check for padding between current and previous partitions
else if (partitions[i].ptEntry.Offset.Offset > previousPartitionEnd) {
padding.ptEntry.Offset.Offset = previousPartitionEnd;
padding.ptEntry.Length = partitions[i].ptEntry.Offset.Offset - previousPartitionEnd;
padding.type = Types::Padding;
std::vector<CPD_PARTITION_INFO>::iterator iter = partitions.begin();
std::advance(iter, i);
partitions.insert(iter, padding);
}
}
// Check for padding after the last region
if ((UINT64)partitions.back().ptEntry.Offset.Offset + (UINT64)partitions.back().ptEntry.Length < (UINT64)region.size()) {
padding.ptEntry.Offset.Offset = partitions.back().ptEntry.Offset.Offset + partitions.back().ptEntry.Length;
padding.ptEntry.Length = (UINT32)region.size() - padding.ptEntry.Offset.Offset;
padding.type = Types::Padding;
partitions.push_back(padding);
}
// Partition map is consistent
for (size_t i = 0; i < partitions.size(); i++) {
if (partitions[i].type == Types::CpdPartition) {
UByteArray partition = region.mid(partitions[i].ptEntry.Offset.Offset, partitions[i].ptEntry.Length);
// Get info
name = usprintf("%c%c%c%c%c%c%c%c%c%c%c%c",
partitions[i].ptEntry.EntryName[0], partitions[i].ptEntry.EntryName[1], partitions[i].ptEntry.EntryName[2], partitions[i].ptEntry.EntryName[3],
partitions[i].ptEntry.EntryName[4], partitions[i].ptEntry.EntryName[5], partitions[i].ptEntry.EntryName[6], partitions[i].ptEntry.EntryName[7],
partitions[i].ptEntry.EntryName[8], partitions[i].ptEntry.EntryName[9], partitions[i].ptEntry.EntryName[10], partitions[i].ptEntry.EntryName[11]);
// It's a manifest
if (name.contains(".man")) {
if (!partitions[i].ptEntry.Offset.HuffmanCompressed
&& partitions[i].ptEntry.Length >= sizeof(CPD_MANIFEST_HEADER)) {
const CPD_MANIFEST_HEADER* manifestHeader = (const CPD_MANIFEST_HEADER*) partition.constData();
if (manifestHeader->HeaderId == ME_MANIFEST_HEADER_ID) {
UByteArray header = partition.left(manifestHeader->HeaderLength * sizeof(UINT32));
UByteArray body = partition.mid(header.size());
info += usprintf(
"\nHeader type: %u\nHeader length: %Xh (%u)\nHeader version: %Xh\nFlags: %08Xh\nVendor: %Xh\n"
"Date: %Xh\nSize: %Xh (%u)\nVersion: %u.%u.%u.%u\nSecurity version number: %u\nModulus size: %Xh (%u)\nExponent size: %Xh (%u)",
manifestHeader->HeaderType,
manifestHeader->HeaderLength * sizeof(UINT32), manifestHeader->HeaderLength * sizeof(UINT32),
manifestHeader->HeaderVersion,
manifestHeader->Flags,
manifestHeader->Vendor,
manifestHeader->Date,
manifestHeader->Size * sizeof(UINT32), manifestHeader->Size * sizeof(UINT32),
manifestHeader->VersionMajor, manifestHeader->VersionMinor, manifestHeader->VersionBugfix, manifestHeader->VersionBuild,
manifestHeader->SecurityVersion,
manifestHeader->ModulusSize * sizeof(UINT32), manifestHeader->ModulusSize * sizeof(UINT32),
manifestHeader->ExponentSize * sizeof(UINT32), manifestHeader->ExponentSize * sizeof(UINT32));
// Add tree item
UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::ManifestCpdPartition, name, UString(), info, header, body, UByteArray(), Fixed, parent);
// Parse data as extensions area
parseCpdExtensionsArea(partitionIndex);
}
}
}
// It's a metadata
else if (name.contains(".met")) {
info = usprintf("Full size: %Xh (%u)\nEntry offset: %Xh\nEntry length: %Xh\nHuffman compressed: ",
partition.size(), partition.size(),
partitions[i].ptEntry.Offset.Offset,
partitions[i].ptEntry.Length)
+ (partitions[i].ptEntry.Offset.HuffmanCompressed ? "Yes" : "No");
// Calculate SHA256 hash over the metadata and add it to it's info
UByteArray hash(SHA256_DIGEST_SIZE, '\x00');
sha256(partition.constData(), partition.size(), hash.data());
info += UString("\nMetadata hash: ") + UString(hash.toHex().constData());
// Add three item
UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::MetadataCpdPartition, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
// Parse data as extensions area
parseCpdExtensionsArea(partitionIndex);
}
// It's a key
else if (name.contains(".key")) {
info = usprintf("Full size: %Xh (%u)\nEntry offset: %Xh\nEntry length: %Xh\nHuffman compressed: ",
partition.size(), partition.size(),
partitions[i].ptEntry.Offset.Offset,
partitions[i].ptEntry.Length)
+ (partitions[i].ptEntry.Offset.HuffmanCompressed ? "Yes" : "No");
// Calculate SHA256 hash over the key and add it to it's info
UByteArray hash(SHA256_DIGEST_SIZE, '\x00');
sha256(partition.constData(), partition.size(), hash.data());
info += UString("\nHash: ") + UString(hash.toHex().constData());
// Add three item
UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::KeyCpdPartition, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
// Parse data as extensions area
parseCpdExtensionsArea(partitionIndex);
}
// It's a code
else {
info = usprintf("Full size: %Xh (%u)\nEntry offset: %Xh\nEntry length: %Xh\nHuffman compressed: ",
partition.size(), partition.size(),
partitions[i].ptEntry.Offset.Offset,
partitions[i].ptEntry.Length)
+ (partitions[i].ptEntry.Offset.HuffmanCompressed ? "Yes" : "No");
// Calculate SHA256 hash over the code and add it to it's info
UByteArray hash(SHA256_DIGEST_SIZE, '\x00');
sha256(partition.constData(), partition.size(), hash.data());
info += UString("\nHash: ") + UString(hash.toHex().constData());
UModelIndex codeIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::CodeCpdPartition, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
parseRawArea(codeIndex);
}
}
else if (partitions[i].type == Types::Padding) {
UByteArray partition = region.mid(partitions[i].ptEntry.Offset.Offset, partitions[i].ptEntry.Length);
// Get info
name = UString("Padding");
info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size());
// Add tree item
model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
}
else {
msg(usprintf("%s: CPD partition of unknown type found", __FUNCTION__), parent);
return U_INVALID_ME_PARTITION_TABLE;
}
}
return U_SUCCESS;
}
USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index)
{
if (!index.isValid()) {
return U_INVALID_PARAMETER;
}
UByteArray body = model->body(index);
UINT32 offset = 0;
while (offset < (UINT32)body.size()) {
const CPD_EXTENTION_HEADER* extHeader = (const CPD_EXTENTION_HEADER*) (body.constData() + offset);
if (extHeader->Length <= ((UINT32)body.size() - offset)) {
UByteArray partition = body.mid(offset, extHeader->Length);
UString name = cpdExtensionTypeToUstring(extHeader->Type);
UString info = usprintf("Full size: %Xh (%u)\nType: %Xh", partition.size(), partition.size(), extHeader->Type);
// Parse Signed Package Info a bit further
UModelIndex extIndex;
if (extHeader->Type == CPD_EXT_TYPE_SIGNED_PACKAGE_INFO) {
UByteArray header = partition.left(sizeof(CPD_EXT_SIGNED_PACKAGE_INFO));
UByteArray data = partition.mid(header.size());
const CPD_EXT_SIGNED_PACKAGE_INFO* infoHeader = (const CPD_EXT_SIGNED_PACKAGE_INFO*)header.constData();
info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %Xh\n"
"Package name: %c%c%c%c\nVersion control number: %Xh\nSecurity version number: %Xh\n"
"Usage bitmap: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
partition.size(), partition.size(),
header.size(), header.size(),
body.size(), body.size(),
infoHeader->ExtensionType,
infoHeader->PackageName[0], infoHeader->PackageName[1], infoHeader->PackageName[2], infoHeader->PackageName[3],
infoHeader->Vcn,
infoHeader->Svn,
infoHeader->UsageBitmap[0], infoHeader->UsageBitmap[1], infoHeader->UsageBitmap[2], infoHeader->UsageBitmap[3],
infoHeader->UsageBitmap[4], infoHeader->UsageBitmap[5], infoHeader->UsageBitmap[6], infoHeader->UsageBitmap[7],
infoHeader->UsageBitmap[8], infoHeader->UsageBitmap[9], infoHeader->UsageBitmap[10], infoHeader->UsageBitmap[11],
infoHeader->UsageBitmap[12], infoHeader->UsageBitmap[13], infoHeader->UsageBitmap[14], infoHeader->UsageBitmap[15]);
// Add tree item
extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, header, data, UByteArray(), Fixed, index);
parseSignedPackageInfoData(extIndex);
}
// Parse IFWI Partition Manifest a bit further
else if (extHeader->Type == CPD_EXT_TYPE_IFWI_PARTITION_MANIFEST) {
const CPD_EXT_IFWI_PARTITION_MANIFEST* attrHeader = (const CPD_EXT_IFWI_PARTITION_MANIFEST*)partition.constData();
// This hash is stored reversed
// Need to reverse it back to normal
UByteArray hash((const char*)&attrHeader->CompletePartitionHash, sizeof(attrHeader->CompletePartitionHash));
std::reverse(hash.begin(), hash.end());
info = usprintf("Full size: %Xh (%u)\nType: %Xh\n"
"Partition name: %c%c%c%c\nPartition length: %Xh\nPartition version major: %Xh\nPartition version minor: %Xh\n"
"Data format version: %Xh\nInstance ID: %Xh\nHash algorithm: %Xh\nHash size: %Xh\nAction on update: %Xh",
partition.size(), partition.size(),
attrHeader->ExtensionType,
attrHeader->PartitionName[0], attrHeader->PartitionName[1], attrHeader->PartitionName[2], attrHeader->PartitionName[3],
attrHeader->CompletePartitionLength,
attrHeader->PartitionVersionMajor, attrHeader->PartitionVersionMinor,
attrHeader->DataFormatVersion,
attrHeader->InstanceId,
attrHeader->HashAlgorithm,
attrHeader->HashSize,
attrHeader->ActionOnUpdate)
+ UString("\nSupport multiple instances: ") + (attrHeader->SupportMultipleInstances ? "Yes" : "No")
+ UString("\nSupport API version based update: ") + (attrHeader->SupportApiVersionBasedUpdate ? "Yes" : "No")
+ UString("\nObey full update rules: ") + (attrHeader->ObeyFullUpdateRules ? "Yes" : "No")
+ UString("\nIFR enable only: ") + (attrHeader->IfrEnableOnly ? "Yes" : "No")
+ UString("\nAllow cross point update: ") + (attrHeader->AllowCrossPointUpdate ? "Yes" : "No")
+ UString("\nAllow cross hotfix update: ") + (attrHeader->AllowCrossHotfixUpdate ? "Yes" : "No")
+ UString("\nPartial update only: ") + (attrHeader->PartialUpdateOnly ? "Yes" : "No")
+ UString("\nPartition hash: ") + UString(hash.toHex().constData());
// Add tree item
extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index);
}
// Parse Module Attributes a bit further
else if (extHeader->Type == CPD_EXT_TYPE_MODULE_ATTRIBUTES) {
const CPD_EXT_MODULE_ATTRIBUTES* attrHeader = (const CPD_EXT_MODULE_ATTRIBUTES*)partition.constData();
// This hash is stored reversed
// Need to reverse it back to normal
UByteArray hash((const char*)&attrHeader->ImageHash, sizeof(attrHeader->ImageHash));
std::reverse(hash.begin(), hash.end());
info = usprintf("Full size: %Xh (%u)\nType: %Xh\n"
"Compression type: %Xh\nUncompressed size: %Xh (%u)\nCompressed size: %Xh (%u)\nGlobal module ID: %Xh\nImage hash: ",
partition.size(), partition.size(),
attrHeader->ExtensionType,
attrHeader->CompressionType,
attrHeader->UncompressedSize, attrHeader->UncompressedSize,
attrHeader->CompressedSize, attrHeader->CompressedSize,
attrHeader->GlobalModuleId) + UString(hash.toHex().constData());
// Add tree item
extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index);
}
// Parse everything else
else {
// Add tree item, if needed
extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index);
}
if (extHeader->Type > CPD_LAST_KNOWN_EXT_TYPE) {
msg(usprintf("%s: CPD extention of unknown type found", __FUNCTION__), extIndex);
}
offset += extHeader->Length;
}
else break;
// TODO: add padding at the end
}
return U_SUCCESS;
}
USTATUS FfsParser::parseSignedPackageInfoData(const UModelIndex & index)
{
if (!index.isValid()) {
return U_INVALID_PARAMETER;
}
UByteArray body = model->body(index);
UINT32 offset = 0;
while (offset < (UINT32)body.size()) {
const CPD_EXT_SIGNED_PACKAGE_INFO_MODULE* moduleHeader = (const CPD_EXT_SIGNED_PACKAGE_INFO_MODULE*)(body.constData() + offset);
if (sizeof(CPD_EXT_SIGNED_PACKAGE_INFO_MODULE) <= ((UINT32)body.size() - offset)) {
UByteArray module((const char*)moduleHeader, sizeof(CPD_EXT_SIGNED_PACKAGE_INFO_MODULE));
UString name = usprintf("%c%c%c%c%c%c%c%c%c%c%c%c",
moduleHeader->Name[0], moduleHeader->Name[1], moduleHeader->Name[2], moduleHeader->Name[3],
moduleHeader->Name[4], moduleHeader->Name[5], moduleHeader->Name[6], moduleHeader->Name[7],
moduleHeader->Name[8], moduleHeader->Name[9], moduleHeader->Name[10],moduleHeader->Name[11]);
// This hash is stored reversed
// Need to reverse it back to normal
UByteArray hash((const char*)&moduleHeader->MetadataHash, sizeof(moduleHeader->MetadataHash));
std::reverse(hash.begin(), hash.end());
UString info = usprintf("Full size: %X (%u)\nType: %Xh\nHash algorithm: %Xh\nHash size: %Xh (%u)\nMetadata size: %Xh (%u)\nMetadata hash: ",
module.size(), module.size(),
moduleHeader->Type,
moduleHeader->HashAlgorithm,
moduleHeader->HashSize, moduleHeader->HashSize,
moduleHeader->MetadataSize, moduleHeader->MetadataSize) + UString(hash.toHex().constData());
// Add tree otem
model->addItem(offset, Types::CpdSpiEntry, 0, name, UString(), info, UByteArray(), module, UByteArray(), Fixed, index);
offset += module.size();
}
else break;
// TODO: add padding at the end
}
return U_SUCCESS;
}

View File

@ -97,6 +97,11 @@ private:
USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseBpdtRegion(const UByteArray & region, const UINT32 localOffset, const UINT32 sbpdtOffsetFixup, const UModelIndex & parent, UModelIndex & index);
USTATUS parseCpdRegion(const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseCpdExtensionsArea(const UModelIndex & index);
USTATUS parseSignedPackageInfoData(const UModelIndex & index);
USTATUS parseRawArea(const UModelIndex & index); USTATUS parseRawArea(const UModelIndex & index);
USTATUS parseVolumeHeader(const UByteArray & volume, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index); USTATUS parseVolumeHeader(const UByteArray & volume, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseVolumeBody(const UModelIndex & index); USTATUS parseVolumeBody(const UModelIndex & index);
@ -163,6 +168,10 @@ private:
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT #ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
friend class NvramParser; // Make FFS parsing routines accessible to NvramParser friend class NvramParser; // Make FFS parsing routines accessible to NvramParser
#endif #endif
#ifdef U_ENABLE_ME_PARSING_SUPPORT
friend class MeParser; // Make FFS parsing routines accessible to MeParser
#endif
}; };
#endif // FFSPARSER_H #endif // FFSPARSER_H

View File

@ -18,9 +18,6 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
// Make sure we use right packing rules // Make sure we use right packing rules
#pragma pack(push, 1) #pragma pack(push, 1)
const UByteArray ME_VERSION_SIGNATURE("\x24\x4D\x41\x4E", 4); //$MAN
const UByteArray ME_VERSION_SIGNATURE2("\x24\x4D\x4E\x32", 4); //$MN2
typedef struct ME_VERSION_ { typedef struct ME_VERSION_ {
UINT32 Signature; UINT32 Signature;
UINT32 Reserved; UINT32 Reserved;
@ -30,6 +27,73 @@ typedef struct ME_VERSION_ {
UINT16 Build; UINT16 Build;
} ME_VERSION; } ME_VERSION;
const UByteArray ME_VERSION_SIGNATURE("\x24\x4D\x41\x4E", 4); //$MAN
const UByteArray ME_VERSION_SIGNATURE2("\x24\x4D\x4E\x32", 4); //$MN2
// FPT
#define ME_ROM_BYPASS_VECTOR_SIZE 0x10
const UByteArray FPT_HEADER_SIGNATURE("\x24\x46\x50\x54", 4); //$FPT
typedef struct FPT_HEADER_ {
UINT32 Signature;
UINT32 NumEntries;
UINT8 HeaderVersion;
UINT8 EntryVersion;
UINT8 HeaderLength;
UINT8 Checksum; // One bit for Redundant before IFWI
UINT16 TicksToAdd;
UINT16 TokensToAdd;
UINT32 UmaSize; // Flags in SPS
UINT32 FlashLayout; // Crc32 before IFWI
UINT16 FitcMajor;
UINT16 FitcMinor;
UINT16 FitcHotfix;
UINT16 FitcBuild;
} FPT_HEADER;
typedef struct FPT_HEADER_ENTRY_{
CHAR8 Name[4];
CHAR8 Owner[4];
UINT32 Offset;
UINT32 Size;
UINT32 Reserved[3];
UINT8 Type : 7;
UINT8 CopyToDramCache : 1;
UINT8 Reserved1 : 7;
UINT8 BuiltWithLength1 : 1;
UINT8 BuiltWithLength2 : 1;
UINT8 Reserved2 : 7;
UINT8 EntryValid;
} FPT_HEADER_ENTRY;
// IFWI
typedef struct IFWI_HEADER_ENTRY_ {
UINT32 Offset;
UINT32 Size;
} IFWI_HEADER_ENTRY;
// IFWI 1.6 (ME), 2.0 (BIOS)
typedef struct IFWI_16_LAYOUT_HEADER_ {
UINT8 RomBypassVector[16];
IFWI_HEADER_ENTRY DataPartition;
IFWI_HEADER_ENTRY BootPartition[5];
UINT64 Checksum;
} IFWI_16_LAYOUT_HEADER;
// IFWI 1.7 (ME)
typedef struct IFWI_17_LAYOUT_HEADER_ {
UINT8 RomBypassVector[16];
UINT16 HeaderSize;
UINT8 Flags;
UINT8 Reserved;
UINT32 Checksum;
IFWI_HEADER_ENTRY DataPartition;
IFWI_HEADER_ENTRY BootPartition[5];
IFWI_HEADER_ENTRY TempPage;
} IFWI_17_LAYOUT_HEADER;
#define ME_MANIFEST_HEADER_ID 0x324E4D24 //$MN2
// Restore previous packing rules // Restore previous packing rules
#pragma pack(pop) #pragma pack(pop)

File diff suppressed because it is too large Load Diff

View File

@ -21,208 +21,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "ustring.h" #include "ustring.h"
#include "ubytearray.h" #include "ubytearray.h"
#include "treemodel.h" #include "treemodel.h"
#include "ffsparser.h"
#include "sha256.h" #include "sha256.h"
#ifdef U_ENABLE_ME_PARSING_SUPPORT #ifdef U_ENABLE_ME_PARSING_SUPPORT
// FPT
#define ME_ROM_BYPASS_VECTOR_SIZE 0x10
const UByteArray ME_FPT_HEADER_SIGNATURE("\x24\x46\x50\x54", 4); //$FPT
typedef struct ME_FPT_HEADER_ {
UINT32 Signature;
UINT32 NumEntries;
UINT8 HeaderVersion;
UINT8 EntryVersion;
UINT8 HeaderLength;
UINT8 Checksum; // One bit for Redundant before IFWI
UINT16 TicksToAdd;
UINT16 TokensToAdd;
UINT32 UmaSize; // Flags in SPS
UINT32 FlashLayout; // Crc32 before IFWI
UINT16 FitcMajor;
UINT16 FitcMinor;
UINT16 FitcHotfix;
UINT16 FitcBuild;
} ME_FPT_HEADER;
typedef struct ME_FPT_ENTRY_{
CHAR8 PartitionName[4];
UINT8 Reserved1;
UINT32 Offset;
UINT32 Length;
UINT8 Reserved2[12];
UINT32 PartitionType : 7;
UINT32 CopyToDramCache : 1;
UINT32 Reserved3 : 7;
UINT32 BuiltWithLength1 : 1;
UINT32 BuiltWithLength2 : 1;
UINT32 Reserved4 : 7;
UINT32 EntryValid : 8;
} ME_FPT_ENTRY;
// IFWI
typedef struct ME_IFWI_LAYOUT_HEADER_ {
UINT8 RomBypassVector[16];
UINT32 DataPartitionOffset;
UINT32 DataPartitionSize;
UINT32 Boot1Offset;
UINT32 Boot1Size;
UINT32 Boot2Offset;
UINT32 Boot2Size;
UINT32 Boot3Offset;
UINT32 Boot3Size;
} ME_IFWI_LAYOUT_HEADER;
// BPDT
const UByteArray ME_BPDT_GREEN_SIGNATURE("\xAA\x55\x00\x00", 4); //0x000055AA
const UByteArray ME_BPDT_YELLOW_SIGNATURE("\xAA\x55\xAA\x00", 4); //0x00AA55AA
typedef struct ME_BPDT_HEADER_ {
UINT32 Signature;
UINT16 NumEntries;
UINT16 Version;
UINT32 Checksum;
UINT32 IfwiVersion;
UINT16 FitcMajor;
UINT16 FitcMinor;
UINT16 FitcHotfix;
UINT16 FitcBuild;
} ME_BPDT_HEADER ;
typedef struct ME_BPDT_ENTRY_ {
UINT32 Type : 16;
UINT32 SplitSubPartitionFirstPart : 1;
UINT32 SplitSubPartitionSecondPart : 1;
UINT32 CodeSubPartition : 1;
UINT32 UmaCachable : 1;
UINT32 Reserved: 12;
UINT32 Offset;
UINT32 Length;
} ME_BPDT_ENTRY;
// CPD
const UByteArray ME_CPD_SIGNATURE("\x24\x43\x50\x44", 4); //$CPD
typedef struct ME_CPD_HEADER_ {
UINT32 Signature;
UINT32 NumEntries;
UINT8 HeaderVersion;
UINT8 EntryVersion;
UINT8 HeaderLength;
UINT8 HeaderChecksum;
UINT8 ShortName[4];
} ME_CPD_HEADER;
typedef struct ME_BPDT_CPD_ENTRY_ {
UINT8 EntryName[12];
struct {
UINT32 Offset : 25;
UINT32 HuffmanCompressed : 1;
UINT32 Reserved : 6;
} Offset;
UINT32 Length;
UINT32 Reserved;
} ME_BPDT_CPD_ENTRY;
typedef struct ME_CPD_MANIFEST_HEADER_ {
UINT32 HeaderType;
UINT32 HeaderLength;
UINT32 HeaderVersion;
UINT32 Flags;
UINT32 Vendor;
UINT32 Date;
UINT32 Size;
UINT32 HeaderId;
UINT32 Reserved1;
UINT16 VersionMajor;
UINT16 VersionMinor;
UINT16 VersionBugfix;
UINT16 VersionBuild;
UINT32 SecurityVersion;
UINT8 Reserved2[8];
UINT8 Reserved3[64];
UINT32 ModulusSize;
UINT32 ExponentSize;
//manifest_rsa_key_t public_key;
//manifest_signature_t signature;
} ME_CPD_MANIFEST_HEADER;
typedef struct ME_CPD_EXTENTION_HEADER_ {
UINT32 Type;
UINT32 Length;
} ME_CPD_EXTENTION_HEADER;
typedef struct ME_CPD_EXT_SIGNED_PACKAGE_INFO_MODULES_ {
UINT8 Name[12];
UINT8 Type;
UINT8 HashAlgorithm;
UINT16 HashSize;
UINT32 MetadataSize;
UINT8 MetadataHash[32];
} ME_CPD_EXT_SIGNED_PACKAGE_INFO_MODULES;
typedef struct ME_CPD_EXT_SIGNED_PACKAGE_INFO_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 PackageName[4];
UINT32 Vcn;
UINT8 UsageBitmap[16];
UINT32 Svn;
UINT8 Reserved[16];
// ME_EXT_SIGNED_PACKAGE_INFO_MODULES Modules[];
} ME_CPD_EXT_SIGNED_PACKAGE_INFO;
typedef struct ME_CPD_EXT_MODULE_ATTRIBUTES_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 CompressionType;
UINT8 Reserved[3];
UINT32 UncompressedSize;
UINT32 CompressedSize;
UINT32 GlobalModuleId;
UINT8 ImageHash[32];
} ME_CPD_EXT_MODULE_ATTRIBUTES;
typedef struct ME_CPD_EXT_IFWI_PARTITION_MANIFEST_ {
UINT32 ExtensionType;
UINT32 ExtensionLength;
UINT8 PartitionName[4];
UINT32 CompletePartitionLength;
UINT16 PartitionVersionMinor;
UINT16 PartitionVersionMajor;
UINT32 DataFormatVersion;
UINT32 InstanceId;
UINT32 SupportMultipleInstances : 1;
UINT32 SupportApiVersionBasedUpdate : 1;
UINT32 ActionOnUpdate : 2;
UINT32 ObeyFullUpdateRules : 1;
UINT32 IfrEnableOnly : 1;
UINT32 AllowCrossPointUpdate : 1;
UINT32 AllowCrossHotfixUpdate : 1;
UINT32 PartialUpdateOnly : 1;
UINT32 ReservedFlags : 23;
UINT32 HashAlgorithm : 8;
UINT32 HashSize : 24;
UINT8 CompletePartitionHash[32];
UINT8 Reserved[20];
} ME_CPD_EXT_IFWI_PARTITION_MANIFEST;
#define ME_MODULE_COMPRESSION_TYPE_UNCOMPRESSED 0
#define ME_MODULE_COMPRESSION_TYPE_HUFFMAN 1
#define ME_MODULE_COMPRESSION_TYPE_LZMA 2
#define ME_MANIFEST_HEADER_ID 0x324E4D24 //$MN2
class MeParser class MeParser
{ {
public: public:
// Default constructor and destructor // Default constructor and destructor
MeParser(TreeModel* treeModel) : model(treeModel) {} MeParser(TreeModel* treeModel, FfsParser* parser) : model(treeModel), ffsParser(parser) {}
~MeParser() {} ~MeParser() {}
// Returns messages // Returns messages
@ -232,9 +39,9 @@ public:
// ME parsing // ME parsing
USTATUS parseMeRegionBody(const UModelIndex & index); USTATUS parseMeRegionBody(const UModelIndex & index);
private: private:
TreeModel *model; TreeModel *model;
FfsParser *ffsParser;
std::vector<std::pair<UString, UModelIndex> > messagesVector; std::vector<std::pair<UString, UModelIndex> > messagesVector;
void msg(const UString message, const UModelIndex index = UModelIndex()) { void msg(const UString message, const UModelIndex index = UModelIndex()) {
@ -242,19 +49,15 @@ private:
} }
USTATUS parseFptRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index); USTATUS parseFptRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index);
USTATUS parseIfwiRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index); USTATUS parseIfwi16Region(const UByteArray & region, const UModelIndex & parent, UModelIndex & index);
USTATUS parseBpdtRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index); USTATUS parseIfwi17Region(const UByteArray & region, const UModelIndex & parent, UModelIndex & index);
USTATUS parseCodePartitionDirectory(const UByteArray & directory, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
USTATUS parseExtensionsArea(const UModelIndex & index);
USTATUS parseSignedPackageInfoData(const UModelIndex & index);
}; };
#else #else
class MeParser class MeParser
{ {
public: public:
// Default constructor and destructor // Default constructor and destructor
MeParser(TreeModel* treeModel) { U_UNUSED_PARAMETER(treeModel); } MeParser(TreeModel* treeModel, FfsParser* parser) { U_UNUSED_PARAMETER(treeModel); U_UNUSED_PARAMETER(parser); }
~MeParser() {} ~MeParser() {}
// Returns messages // Returns messages

View File

@ -86,6 +86,11 @@ public:
return UByteArray(hex); return UByteArray(hex);
} }
std::basic_string<char>::iterator begin() {return d.begin();}
std::basic_string<char>::iterator end() {return d.end();}
std::basic_string<char>::const_iterator begin() const {return d.begin();}
std::basic_string<char>::const_iterator end() const {return d.end();}
private: private:
std::basic_string<char> d; std::basic_string<char> d;
}; };
@ -97,3 +102,4 @@ inline const UByteArray operator+(const UByteArray &a1, const UByteArray &a2)
#endif // QT_CORE_LIB #endif // QT_CORE_LIB
#endif // UBYTEARRAY_H #endif // UBYTEARRAY_H