add FFSv3 support with large files and large sections

This commit is contained in:
Alex Matrosov 2017-12-10 16:54:40 -08:00
parent 75225ecc28
commit 73019876cf
6 changed files with 212 additions and 133 deletions

View File

@ -1,6 +1,6 @@
/* uefipatch_main.cpp /* uefipatch_main.cpp
Copyright (c) 2015, Nikolaj Schlej. All rights reserved. Copyright (c) 2017, LongSoft. All rights reserved.
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -19,8 +19,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication a(argc, argv); QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush"); a.setOrganizationName("LongSoft");
a.setOrganizationDomain("coderush.me"); a.setOrganizationDomain("longsoft.me");
a.setApplicationName("UEFIPatch"); a.setApplicationName("UEFIPatch");
UEFIPatch w; UEFIPatch w;
@ -31,7 +31,7 @@ int main(int argc, char *argv[])
result = w.patchFromFile(a.arguments().at(1)); result = w.patchFromFile(a.arguments().at(1));
} }
else { else {
std::cout << "UEFIPatch 0.3.9 - UEFI image file patching utility" << std::endl << std::endl << std::cout << "UEFIPatch 0.3.10 - UEFI image file patching utility" << std::endl << std::endl <<
"Usage: UEFIPatch image_file" << std::endl << std::endl << "Usage: UEFIPatch image_file" << std::endl << std::endl <<
"Patches will be read from patches.txt file\n"; "Patches will be read from patches.txt file\n";
return ERR_SUCCESS; return ERR_SUCCESS;

23
ffs.cpp
View File

@ -30,7 +30,10 @@ const QVector<QByteArray> FFSv3Volumes =
const UINT8 ffsAlignmentTable[] = const UINT8 ffsAlignmentTable[] =
{ 0, 4, 7, 9, 10, 12, 15, 16 }; { 0, 4, 7, 9, 10, 12, 15, 16 };
UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize) const UINT8 ffsAlignment2Table[] =
{ 17, 18, 19, 20, 21, 22, 23, 24 };
UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize)
{ {
if (!buffer) if (!buffer)
return 0; return 0;
@ -40,7 +43,15 @@ UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
while (bufferSize--) while (bufferSize--)
counter += buffer[bufferSize]; counter += buffer[bufferSize];
return (UINT8)0x100 - counter; return counter;
}
UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize)
{
if (!buffer)
return 0;
return (UINT8)0x100 - calculateSum8(buffer, bufferSize);
} }
UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize) UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize)
@ -120,6 +131,8 @@ QString fileTypeToQString(const UINT8 type)
case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: return QObject::tr("Volume image"); case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: return QObject::tr("Volume image");
case EFI_FV_FILETYPE_COMBINED_SMM_DXE: return QObject::tr("Combined SMM/DXE"); case EFI_FV_FILETYPE_COMBINED_SMM_DXE: return QObject::tr("Combined SMM/DXE");
case EFI_FV_FILETYPE_SMM_CORE: return QObject::tr("SMM core"); case EFI_FV_FILETYPE_SMM_CORE: return QObject::tr("SMM core");
case EFI_FV_FILETYPE_SMM_STANDALONE: return QObject::tr("SMM standalone");
case EFI_FV_FILETYPE_SMM_CORE_STANDALONE: return QObject::tr("SMM core standalone");
case EFI_FV_FILETYPE_PAD: return QObject::tr("Pad"); case EFI_FV_FILETYPE_PAD: return QObject::tr("Pad");
default: return QObject::tr("Unknown"); default: return QObject::tr("Unknown");
}; };
@ -155,10 +168,10 @@ UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header)
if (!header) if (!header)
return 0; return 0;
const bool extended = false; bool extended = false;
/*if (uint24ToUint32(header->Size) == EFI_SECTION2_IS_USED) { if (uint24ToUint32(header->Size) == EFI_SECTION2_IS_USED) {
extended = true; extended = true;
}*/ }
switch (header->Type) switch (header->Type)
{ {

14
ffs.h
View File

@ -292,7 +292,7 @@ UINT8 Type;
UINT8 Attributes; UINT8 Attributes;
UINT8 Size[3]; // Set to 0xFFFFFF UINT8 Size[3]; // Set to 0xFFFFFF
UINT8 State; UINT8 State;
UINT32 ExtendedSize; UINT64 ExtendedSize;
} EFI_FFS_FILE_HEADER2; } EFI_FFS_FILE_HEADER2;
// Standard data checksum, used if FFS_ATTRIB_CHECKSUM is clear // Standard data checksum, used if FFS_ATTRIB_CHECKSUM is clear
@ -314,6 +314,8 @@ UINT32 ExtendedSize;
#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B #define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B
#define EFI_FV_FILETYPE_COMBINED_SMM_DXE 0x0C #define EFI_FV_FILETYPE_COMBINED_SMM_DXE 0x0C
#define EFI_FV_FILETYPE_SMM_CORE 0x0D #define EFI_FV_FILETYPE_SMM_CORE 0x0D
#define EFI_FV_FILETYPE_SMM_STANDALONE 0x0E
#define EFI_FV_FILETYPE_SMM_CORE_STANDALONE 0x0F
#define EFI_FV_FILETYPE_OEM_MIN 0xC0 #define EFI_FV_FILETYPE_OEM_MIN 0xC0
#define EFI_FV_FILETYPE_OEM_MAX 0xDF #define EFI_FV_FILETYPE_OEM_MAX 0xDF
#define EFI_FV_FILETYPE_DEBUG_MIN 0xE0 #define EFI_FV_FILETYPE_DEBUG_MIN 0xE0
@ -326,6 +328,7 @@ UINT32 ExtendedSize;
#define FFS_ATTRIB_TAIL_PRESENT 0x01 // Valid only for revision 1 volumes #define FFS_ATTRIB_TAIL_PRESENT 0x01 // Valid only for revision 1 volumes
#define FFS_ATTRIB_RECOVERY 0x02 // Valid only for revision 1 volumes #define FFS_ATTRIB_RECOVERY 0x02 // Valid only for revision 1 volumes
#define FFS_ATTRIB_LARGE_FILE 0x01 // Valid only for FFSv3 volumes #define FFS_ATTRIB_LARGE_FILE 0x01 // Valid only for FFSv3 volumes
#define FFS_ATTRIB_DATA_ALIGNMENT2 0x02 // Valid only for revision 2 volumes
#define FFS_ATTRIB_FIXED 0x04 #define FFS_ATTRIB_FIXED 0x04
#define FFS_ATTRIB_DATA_ALIGNMENT 0x38 #define FFS_ATTRIB_DATA_ALIGNMENT 0x38
#define FFS_ATTRIB_CHECKSUM 0x40 #define FFS_ATTRIB_CHECKSUM 0x40
@ -333,6 +336,9 @@ UINT32 ExtendedSize;
// FFS alignment table // FFS alignment table
extern const UINT8 ffsAlignmentTable[]; extern const UINT8 ffsAlignmentTable[];
// Extended FFS alignment table
extern const UINT8 ffsAlignment2Table[];
// File states // File states
#define EFI_FILE_HEADER_CONSTRUCTION 0x01 #define EFI_FILE_HEADER_CONSTRUCTION 0x01
#define EFI_FILE_HEADER_VALID 0x02 #define EFI_FILE_HEADER_VALID 0x02
@ -360,7 +366,9 @@ const QByteArray EFI_FFS_PAD_FILE_GUID
// FFS size conversion routines // FFS size conversion routines
extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize); extern VOID uint32ToUint24(UINT32 size, UINT8* ffsSize);
extern UINT32 uint24ToUint32(const UINT8* ffsSize); extern UINT32 uint24ToUint32(const UINT8* ffsSize);
// FFS file 8bit checksum calculation routine
// FFS file 8bit checksum calculation routines
extern UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize);
extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize); extern UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize);
//***************************************************************************** //*****************************************************************************
@ -528,7 +536,7 @@ typedef EFI_COMMON_SECTION_HEADER2 EFI_FIRMWARE_VOLUME_IMAGE_SECTION2;
typedef EFI_COMMON_SECTION_HEADER EFI_USER_INTERFACE_SECTION; typedef EFI_COMMON_SECTION_HEADER EFI_USER_INTERFACE_SECTION;
typedef EFI_COMMON_SECTION_HEADER2 EFI_USER_INTERFACE_SECTION2; typedef EFI_COMMON_SECTION_HEADER2 EFI_USER_INTERFACE_SECTION2;
//Section routines // Section routines
extern UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header); extern UINT32 sizeOfSectionHeader(const EFI_COMMON_SECTION_HEADER* header);
//***************************************************************************** //*****************************************************************************

View File

@ -287,15 +287,9 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase); const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase);
// Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency // Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency
UINT8 descriptorVersion = 0; UINT8 descriptorVersion = 2; // Skylake+ by default
if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ) // Old descriptor if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ) // Old descriptor
descriptorVersion = 1; descriptorVersion = 1;
else if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor
descriptorVersion = 2;
else {
msg(tr("parseIntelImage: unknown descriptor version with ReadClockFrequency %1h").hexarg(componentSection->FlashParameters.ReadClockFrequency));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// ME region // ME region
QByteArray me; QByteArray me;
@ -983,15 +977,16 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
else else
headerSize = volumeHeader->HeaderLength; headerSize = volumeHeader->HeaderLength;
// Sanity check after some new crazy MSI images // Sanity check after some crazy MSI images
headerSize = ALIGN8(headerSize); headerSize = ALIGN8(headerSize);
// Check for volume structure to be known // Check for FFS v2/v3 volume
bool volumeIsUnknown = true; UINT8 subtype = Subtypes::UnknownVolume;
if (FFSv2Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))){
// Check for FFS v2 volume subtype = Subtypes::Ffs2Volume;
if (FFSv2Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) { }
volumeIsUnknown = false; else if (FFSv3Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) {
subtype = Subtypes::Ffs3Volume;
} }
// Check attributes // Check attributes
@ -1063,10 +1058,10 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Add tree item // Add tree item
QByteArray header = volume.left(headerSize); QByteArray header = volume.left(headerSize);
QByteArray body = volume.mid(headerSize, volumeSize - headerSize); QByteArray body = volume.mid(headerSize, volumeSize - headerSize);
index = model->addItem(Types::Volume, volumeIsUnknown ? Subtypes::UnknownVolume : Subtypes::Ffs2Volume, COMPRESSION_ALGORITHM_NONE, name, text, info, header, body, parent, mode); index = model->addItem(Types::Volume, subtype, COMPRESSION_ALGORITHM_NONE, name, text, info, header, body, parent, mode);
// Show messages // Show messages
if (volumeIsUnknown) { if (subtype == Subtypes::UnknownVolume) {
msg(tr("parseVolume: unknown file system %1").arg(guidToQString(volumeHeader->FileSystemGuid)), index); msg(tr("parseVolume: unknown file system %1").arg(guidToQString(volumeHeader->FileSystemGuid)), index);
// Do not parse unknown volumes // Do not parse unknown volumes
return ERR_SUCCESS; return ERR_SUCCESS;
@ -1100,19 +1095,42 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
break; break;
} }
result = getFileSize(volume, fileOffset, fileSize); QByteArray tempFile = volume.mid(fileOffset, sizeof(EFI_FFS_FILE_HEADER));
if (result) const EFI_FFS_FILE_HEADER* tempFileHeader = (const EFI_FFS_FILE_HEADER*)tempFile.constData();
return result; UINT32 fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
fileSize = uint24ToUint32(tempFileHeader->Size);
if (volumeHeader->Revision > 1 && (tempFileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
// Check if it's possibly the latest file in the volume
if (volumeSize - fileOffset < sizeof(EFI_FFS_FILE_HEADER2)) {
// No files are possible after this point
// All the rest is either free space or non-UEFI data
QByteArray rest = volume.right(volumeSize - fileOffset);
if (rest.count(empty) == rest.size()) { // It's a free space
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index);
}
else { //It's non-UEFI data
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index);
msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex);
}
// Exit from loop
break;
}
// Check file size to be at least size of EFI_FFS_FILE_HEADER fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
if (fileSize < sizeof(EFI_FFS_FILE_HEADER)) { tempFile = volume.mid(fileOffset, sizeof(EFI_FFS_FILE_HEADER2));
const EFI_FFS_FILE_HEADER2* tempFileHeader2 = (const EFI_FFS_FILE_HEADER2*)tempFile.constData();
fileSize = (UINT32)tempFileHeader2->ExtendedSize;
}
// Check file size to be at least size of the header
if (fileSize < fileHeaderSize) {
msg(tr("parseVolume: volume has FFS file with invalid size"), index); msg(tr("parseVolume: volume has FFS file with invalid size"), index);
return ERR_INVALID_FILE; return ERR_INVALID_FILE;
} }
QByteArray file = volume.mid(fileOffset, fileSize); QByteArray file = volume.mid(fileOffset, fileSize);
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER)); QByteArray header = file.left(fileHeaderSize);
// If we are at empty space in the end of volume // If we are at empty space in the end of volume
if (header.count(empty) == header.size()) { if (header.count(empty) == header.size()) {
// Check free space to be actually free // Check free space to be actually free
@ -1152,8 +1170,11 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Check file alignment // Check file alignment
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData(); const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData();
UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3]; UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
UINT32 alignment = (UINT32)pow(2.0, alignmentPower); if (volumeHeader->Revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2))
if ((fileOffset + sizeof(EFI_FFS_FILE_HEADER)) % alignment) alignmentPower = ffsAlignment2Table[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
UINT32 alignment = (UINT32)(1UL << alignmentPower);
if ((fileOffset + fileHeaderSize) % alignment)
msgUnalignedFile = true; msgUnalignedFile = true;
// Check file GUID // Check file GUID
@ -1165,7 +1186,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Parse file // Parse file
QModelIndex fileIndex; QModelIndex fileIndex;
result = parseFile(file, fileIndex, empty == '\xFF' ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index); result = parseFile(file, fileIndex, volumeHeader->Revision, empty == '\xFF' ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index);
if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME)
msg(tr("parseVolume: FFS file parsing failed with error \"%1\"").arg(errorMessage(result)), index); msg(tr("parseVolume: FFS file parsing failed with error \"%1\"").arg(errorMessage(result)), index);
@ -1183,16 +1204,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize) UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const UINT8 revision, const UINT8 erasePolarity, const QModelIndex & parent, const UINT8 mode)
{
if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER))
return ERR_INVALID_VOLUME;
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)(volume.constData() + fileOffset);
fileSize = uint24ToUint32(fileHeader->Size);
return ERR_SUCCESS;
}
UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const UINT8 erasePolarity, const QModelIndex & parent, const UINT8 mode)
{ {
bool msgInvalidHeaderChecksum = false; bool msgInvalidHeaderChecksum = false;
bool msgInvalidDataChecksum = false; bool msgInvalidDataChecksum = false;
@ -1200,43 +1212,32 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
bool msgInvalidType = false; bool msgInvalidType = false;
// Populate file header // Populate file header
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER))
return ERR_INVALID_FILE;
const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)file.constData(); const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)file.constData();
// Check file state
// Construct empty byte for this file // Construct empty byte for this file
char empty = erasePolarity ? '\xFF' : '\x00'; char empty = erasePolarity ? '\xFF' : '\x00';
// Check header checksum // Get file header
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER)); QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
QByteArray tempHeader = header; if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*)(tempHeader.data()); if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER2))
tempFileHeader->IntegrityCheck.Checksum.Header = 0; return ERR_INVALID_FILE;
tempFileHeader->IntegrityCheck.Checksum.File = 0; header = file.left(sizeof(EFI_FFS_FILE_HEADER2));
UINT8 calculated = calculateChecksum8((const UINT8*)tempFileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1); }
if (fileHeader->IntegrityCheck.Checksum.Header != calculated)
// Check header checksum
UINT8 calculatedHeader = 0x100 -(calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State);
if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader)
msgInvalidHeaderChecksum = true; msgInvalidHeaderChecksum = true;
// Check data checksum
// Data checksum must be calculated
if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
UINT32 bufferSize = file.size() - sizeof(EFI_FFS_FILE_HEADER);
// Exclude file tail from data checksum calculation
if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
bufferSize -= sizeof(UINT16);
calculated = calculateChecksum8((const UINT8*)(file.constData() + sizeof(EFI_FFS_FILE_HEADER)), bufferSize);
if (fileHeader->IntegrityCheck.Checksum.File != calculated)
msgInvalidDataChecksum = true;
}
// Data checksum must be one of predefined values
else if (fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM && fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2)
msgInvalidDataChecksum = true;
// Get file body // Get file body
QByteArray body = file.right(file.size() - sizeof(EFI_FFS_FILE_HEADER)); QByteArray body = file.mid(header.size());
// Check for file tail presence // Check for file tail presence
QByteArray tail; QByteArray tail;
if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) if (revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
{
//Check file tail; //Check file tail;
tail = body.right(sizeof(UINT16)); tail = body.right(sizeof(UINT16));
UINT16 tailValue = *(UINT16*)tail.constData(); UINT16 tailValue = *(UINT16*)tail.constData();
@ -1247,48 +1248,47 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
body = body.left(body.size() - sizeof(UINT16)); body = body.left(body.size() - sizeof(UINT16));
} }
// Check data checksum
// Data checksum must be calculated
UINT8 calculatedData = 0;
if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
calculatedData = calculateChecksum8((const UINT8*)body.constData(), body.size());
if (fileHeader->IntegrityCheck.Checksum.File != calculatedData)
msgInvalidDataChecksum = true;
}
// Data checksum must be one of predefined values
else if ((revision == 1 && fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM)
|| fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2)
msgInvalidDataChecksum = true;
// Parse current file by default // Parse current file by default
bool parseCurrentFile = true; bool parseCurrentFile = false;
bool parseAsBios = false; bool parseAsBios = false;
// Check file type // Check file type
switch (fileHeader->Type) switch (fileHeader->Type) {
{
case EFI_FV_FILETYPE_ALL: case EFI_FV_FILETYPE_ALL:
parseAsBios = true;
break;
case EFI_FV_FILETYPE_RAW: case EFI_FV_FILETYPE_RAW:
parseAsBios = true; parseAsBios = true;
break;
case EFI_FV_FILETYPE_FREEFORM: case EFI_FV_FILETYPE_FREEFORM:
break;
case EFI_FV_FILETYPE_SECURITY_CORE: case EFI_FV_FILETYPE_SECURITY_CORE:
break;
case EFI_FV_FILETYPE_PEI_CORE: case EFI_FV_FILETYPE_PEI_CORE:
break;
case EFI_FV_FILETYPE_DXE_CORE: case EFI_FV_FILETYPE_DXE_CORE:
break;
case EFI_FV_FILETYPE_PEIM: case EFI_FV_FILETYPE_PEIM:
break;
case EFI_FV_FILETYPE_DRIVER: case EFI_FV_FILETYPE_DRIVER:
break;
case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
break;
case EFI_FV_FILETYPE_APPLICATION: case EFI_FV_FILETYPE_APPLICATION:
break;
case EFI_FV_FILETYPE_SMM: case EFI_FV_FILETYPE_SMM:
break;
case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
break;
case EFI_FV_FILETYPE_COMBINED_SMM_DXE: case EFI_FV_FILETYPE_COMBINED_SMM_DXE:
break;
case EFI_FV_FILETYPE_SMM_CORE: case EFI_FV_FILETYPE_SMM_CORE:
break; case EFI_FV_FILETYPE_SMM_STANDALONE:
case EFI_FV_FILETYPE_SMM_CORE_STANDALONE:
case EFI_FV_FILETYPE_PAD: case EFI_FV_FILETYPE_PAD:
parseCurrentFile = true;
break; break;
default: default:
msgInvalidType = true; msgInvalidType = true;
parseCurrentFile = false;
}; };
// Check for empty file // Check for empty file
@ -1310,25 +1310,27 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
else else
name = parseAsNonEmptyPadFile ? tr("Non-empty pad-file") : tr("Pad-file"); name = parseAsNonEmptyPadFile ? tr("Non-empty pad-file") : tr("Pad-file");
info = tr("File GUID: %1\nType: %2h\nAttributes: %3h\nFull size: %4h (%5)\nHeader size: %6h (%7)\nBody size: %8h (%9)\nState: %10h") info = tr("File GUID: %1\nType: %2h\nAttributes: %3h\nFull size: %4h (%5)\nHeader size: %6h (%7)\nBody size: %8h (%9)\nState: %10h\nHeader checksum: %11h\nData checksum: %12h")
.arg(guidToQString(fileHeader->Name)) .arg(guidToQString(fileHeader->Name))
.hexarg2(fileHeader->Type, 2) .hexarg2(fileHeader->Type, 2)
.hexarg2(fileHeader->Attributes, 2) .hexarg2(fileHeader->Attributes, 2)
.hexarg(header.size() + body.size() + tail.size()).arg(header.size() + body.size() + tail.size()) .hexarg(header.size() + body.size() + tail.size()).arg(header.size() + body.size() + tail.size())
.hexarg(header.size()).arg(header.size()) .hexarg(header.size()).arg(header.size())
.hexarg(body.size()).arg(body.size()) .hexarg(body.size()).arg(body.size())
.hexarg2(fileHeader->State, 2); .hexarg2(fileHeader->State, 2)
.hexarg2(fileHeader->IntegrityCheck.Checksum.Header, 2)
.hexarg2(fileHeader->IntegrityCheck.Checksum.File, 2);
// Add tree item // Add tree item
index = model->addItem(Types::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode); index = model->addItem(Types::File, fileHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Show messages // Show messages
if (msgInvalidHeaderChecksum) if (msgInvalidHeaderChecksum)
msg(tr("parseFile: invalid header checksum"), index); msg(tr("parseFile: invalid header checksum %1h, should be %2h").hexarg2(fileHeader->IntegrityCheck.Checksum.Header, 2).hexarg2(calculatedHeader, 2), index);
if (msgInvalidDataChecksum) if (msgInvalidDataChecksum)
msg(tr("parseFile: invalid data checksum"), index); msg(tr("parseFile: invalid data checksum %1h, should be %2h").hexarg2(fileHeader->IntegrityCheck.Checksum.File, 2).hexarg2(calculatedData, 2), index);
if (msgInvalidTailValue) if (msgInvalidTailValue)
msg(tr("parseFile: invalid tail value"), index); msg(tr("parseFile: invalid tail value %1h").hexarg(*(UINT16*)tail.data()), index);
if (msgInvalidType) if (msgInvalidType)
msg(tr("parseFile: unknown file type %1h").arg(fileHeader->Type, 2), index); msg(tr("parseFile: unknown file type %1h").arg(fileHeader->Type, 2), index);
@ -1382,8 +1384,15 @@ UINT8 FfsEngine::getSectionSize(const QByteArray & file, const UINT32 sectionOff
{ {
if ((UINT32)file.size() < sectionOffset + sizeof(EFI_COMMON_SECTION_HEADER)) if ((UINT32)file.size() < sectionOffset + sizeof(EFI_COMMON_SECTION_HEADER))
return ERR_INVALID_FILE; return ERR_INVALID_FILE;
const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset); const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset);
sectionSize = uint24ToUint32(sectionHeader->Size); sectionSize = uint24ToUint32(sectionHeader->Size);
// This may introduce a very rare error with a non-extended section of size equal to 0xFFFFFF
if (sectionSize != 0xFFFFFF)
return ERR_SUCCESS;
const EFI_COMMON_SECTION_HEADER2* sectionHeader2 = (const EFI_COMMON_SECTION_HEADER2*)(file.constData() + sectionOffset);
sectionSize = sectionHeader2->ExtendedSize;
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -1670,7 +1679,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
} }
} }
else if (certificateHeader->CertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { else if (certificateHeader->CertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
info += tr("\nSignature type: PCKS7"); info += tr("\nSignature type: PKCS7");
// TODO: show signature info in Information panel // TODO: show signature info in Information panel
} }
else { else {
@ -2219,28 +2228,51 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
if (header.size() != sizeof(EFI_FFS_FILE_HEADER)) if (header.size() != sizeof(EFI_FFS_FILE_HEADER))
return ERR_INVALID_FILE; return ERR_INVALID_FILE;
QByteArray newHeader = header; QByteArray newObject = header + body;
QByteArray newBody = body; EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)newObject.data();
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)newHeader.data();
// Determine correct file header size
bool largeFile = false;
UINT32 headerSize = sizeof(EFI_FFS_FILE_HEADER);
if (revision == 2 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
largeFile = true;
headerSize = sizeof(EFI_FFS_FILE_HEADER2);
}
QByteArray newHeader = newObject.left(headerSize);
QByteArray newBody = newObject.mid(headerSize);
// Check if the file has a tail // Check if the file has a tail
UINT8 tailSize = fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT ? sizeof(UINT16) : 0; UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0;
if (tailSize) { if (tailSize) {
// Remove the tail, it will then be added back for revision 1 volumes // Remove the tail, it will then be added back for revision 1 volumes
newBody = newBody.left(newBody.size() - tailSize); newBody = newBody.left(newBody.size() - tailSize);
// Remove the attribute for rev2+ volumes
if (revision != 1) {
fileHeader->Attributes &= ~(FFS_ATTRIB_TAIL_PRESENT);
}
} }
// Correct file size // Correct file size
uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + newBody.size() + tailSize, fileHeader->Size); if (!largeFile) {
if (newBody.size() >= 0xFFFFFF) {
return ERR_INVALID_FILE;
}
uint32ToUint24(headerSize + newBody.size() + tailSize, fileHeader->Size);
}
else {
uint32ToUint24(0xFFFFFF, fileHeader->Size);
EFI_FFS_FILE_HEADER2* fileHeader2 = (EFI_FFS_FILE_HEADER2*)newHeader.data();
fileHeader2->ExtendedSize = headerSize + newBody.size() + tailSize;
}
// Set file state
UINT8 state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | EFI_FILE_HEADER_CONSTRUCTION;
if (erasePolarity)
state = ~state;
fileHeader->State = state;
// Recalculate header checksum // Recalculate header checksum
fileHeader->IntegrityCheck.Checksum.Header = 0; fileHeader->IntegrityCheck.Checksum.Header = 0;
fileHeader->IntegrityCheck.Checksum.File = 0; fileHeader->IntegrityCheck.Checksum.File = 0;
fileHeader->IntegrityCheck.Checksum.Header = calculateChecksum8((const UINT8*)fileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1); fileHeader->IntegrityCheck.Checksum.Header = 0x100 - (calculateSum8((const UINT8*)newHeader.constData(), headerSize) - fileHeader->State);
// Recalculate data checksum, if needed // Recalculate data checksum, if needed
if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM)
@ -2254,23 +2286,17 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
created.append(newBody); created.append(newBody);
// Append tail, if needed // Append tail, if needed
if (revision ==1 && tailSize) { if (revision == 1 && tailSize) {
UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header; UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header;
UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File; UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File;
created.append(ht).append(ft); created.append(ht).append(ft);
} }
// Set file state
UINT8 state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | EFI_FILE_HEADER_CONSTRUCTION;
if (erasePolarity)
state = ~state;
fileHeader->State = state;
// Prepend header // Prepend header
created.prepend(newHeader); created.prepend(newHeader);
// Parse file // Parse file
result = parseFile(created, fileIndex, erasePolarity ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index, mode); result = parseFile(created, fileIndex, revision, erasePolarity ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE, index, mode);
if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME)
return result; return result;
@ -2428,17 +2454,20 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
} }
else if (model->type(parent) == Types::File) { else if (model->type(parent) == Types::File) {
type = Types::Section; type = Types::Section;
const EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*)object.constData(); const EFI_COMMON_SECTION_HEADER* commonHeader = (const EFI_COMMON_SECTION_HEADER*)object.constData();
headerSize = sizeOfSectionHeader(commonHeader); headerSize = sizeOfSectionHeader(commonHeader);
} }
else if (model->type(parent) == Types::Section) { else if (model->type(parent) == Types::Section) {
type = Types::Section; type = Types::Section;
const EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*)object.constData(); const EFI_COMMON_SECTION_HEADER* commonHeader = (const EFI_COMMON_SECTION_HEADER*)object.constData();
headerSize = sizeOfSectionHeader(commonHeader); headerSize = sizeOfSectionHeader(commonHeader);
} }
else else
return ERR_NOT_IMPLEMENTED; return ERR_NOT_IMPLEMENTED;
if ((UINT32)object.size() < headerSize)
return ERR_BUFFER_TOO_SMALL;
return create(index, type, object.left(headerSize), object.right(object.size() - headerSize), mode, Actions::Insert); return create(index, type, object.left(headerSize), object.right(object.size() - headerSize), mode, Actions::Insert);
} }
@ -2873,6 +2902,9 @@ UINT8 FfsEngine::constructPadFile(const QByteArray &guid, const UINT32 size, con
if (size < sizeof(EFI_FFS_FILE_HEADER) || erasePolarity == ERASE_POLARITY_UNKNOWN) if (size < sizeof(EFI_FFS_FILE_HEADER) || erasePolarity == ERASE_POLARITY_UNKNOWN)
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
if (size >= 0xFFFFFF) // TODO: large file support
return ERR_INVALID_PARAMETER;
pad = QByteArray(size - guid.size(), erasePolarity == ERASE_POLARITY_TRUE ? '\xFF' : '\x00'); pad = QByteArray(size - guid.size(), erasePolarity == ERASE_POLARITY_TRUE ? '\xFF' : '\x00');
pad.prepend(guid); pad.prepend(guid);
EFI_FFS_FILE_HEADER* header = (EFI_FFS_FILE_HEADER*)pad.data(); EFI_FFS_FILE_HEADER* header = (EFI_FFS_FILE_HEADER*)pad.data();
@ -3265,6 +3297,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
model->subtype(index.child(i, 0)) == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)){ model->subtype(index.child(i, 0)) == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)){
QModelIndex peiFile = index.child(i, 0); QModelIndex peiFile = index.child(i, 0);
UINT32 sectionOffset = sizeof(EFI_FFS_FILE_HEADER); UINT32 sectionOffset = sizeof(EFI_FFS_FILE_HEADER);
// BUGBUG: this parsing is bad and doesn't support large files, but it needs to be performed only for very old images with uncompressed DXE volumes, so whatever
// Search for PE32 or TE section // Search for PE32 or TE section
for (int j = 0; j < model->rowCount(peiFile); j++) { for (int j = 0; j < model->rowCount(peiFile); j++) {
if (model->subtype(peiFile.child(j, 0)) == EFI_SECTION_PE32 || if (model->subtype(peiFile.child(j, 0)) == EFI_SECTION_PE32 ||
@ -3330,6 +3363,9 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
continue; continue;
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)file.data(); EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)file.data();
UINT32 fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
if (volumeHeader->Revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE))
fileHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
// Pad file // Pad file
if (fileHeader->Type == EFI_FV_FILETYPE_PAD) { if (fileHeader->Type == EFI_FV_FILETYPE_PAD) {
@ -3357,8 +3393,8 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
UINT8 alignmentPower; UINT8 alignmentPower;
UINT32 alignmentBase; UINT32 alignmentBase;
alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3]; alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
alignment = (UINT32)pow(2.0, alignmentPower); alignment = (UINT32)(1UL <<alignmentPower);
alignmentBase = header.size() + offset + sizeof(EFI_FFS_FILE_HEADER); alignmentBase = header.size() + offset + fileHeaderSize;
if (alignmentBase % alignment) { if (alignmentBase % alignment) {
// File will be unaligned if added as is, so we must add pad file before it // File will be unaligned if added as is, so we must add pad file before it
// Determine pad file size // Determine pad file size
@ -3577,7 +3613,7 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision,
model->action(index) == Actions::Rebuild) { model->action(index) == Actions::Rebuild) {
QByteArray header = model->header(index); QByteArray header = model->header(index);
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)header.data(); EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)header.data();
// Check erase polarity // Check erase polarity
if (erasePolarity == ERASE_POLARITY_UNKNOWN) { if (erasePolarity == ERASE_POLARITY_UNKNOWN) {
msg(tr("reconstructFile: unknown erase polarity"), index); msg(tr("reconstructFile: unknown erase polarity"), index);
@ -3635,6 +3671,10 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision,
// File contains sections // File contains sections
else { else {
UINT32 offset = 0; UINT32 offset = 0;
UINT32 headerSize = sizeof(EFI_FFS_FILE_HEADER);
if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
headerSize = sizeof(EFI_FFS_FILE_HEADER2);
}
for (int i = 0; i < model->rowCount(index); i++) { for (int i = 0; i < model->rowCount(index); i++) {
// Align to 4 byte boundary // Align to 4 byte boundary
@ -3646,7 +3686,7 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision,
} }
// Calculate section base // Calculate section base
UINT32 sectionBase = base ? base + sizeof(EFI_FFS_FILE_HEADER) + offset : 0; UINT32 sectionBase = base ? base + headerSize + offset : 0;
// Reconstruct section // Reconstruct section
QByteArray section; QByteArray section;
@ -3668,13 +3708,22 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision,
// Correct file size // Correct file size
UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0; UINT8 tailSize = (revision == 1 && (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)) ? sizeof(UINT16) : 0;
if (revision > 1 && (fileHeader->Attributes & FFS_ATTRIB_LARGE_FILE)) {
uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize, fileHeader->Size); uint32ToUint24(EFI_SECTION2_IS_USED, fileHeader->Size);
EFI_FFS_FILE_HEADER2* fileHeader2 = (EFI_FFS_FILE_HEADER2*) fileHeader;
fileHeader2->ExtendedSize = sizeof(EFI_FFS_FILE_HEADER2) + reconstructed.size() + tailSize;
} else {
if (sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize > 0xFFFFFF) {
msg(tr("reconstructFile: resulting file size is too big"), index);
return ERR_INVALID_FILE;
}
uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + reconstructed.size() + tailSize, fileHeader->Size);
}
// Recalculate header checksum // Recalculate header checksum
fileHeader->IntegrityCheck.Checksum.Header = 0; fileHeader->IntegrityCheck.Checksum.Header = 0;
fileHeader->IntegrityCheck.Checksum.File = 0; fileHeader->IntegrityCheck.Checksum.File = 0;
fileHeader->IntegrityCheck.Checksum.Header = calculateChecksum8((const UINT8*)fileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1); fileHeader->IntegrityCheck.Checksum.Header = 0x100 - (calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->State);
} }
// Use current file body // Use current file body
else else
@ -3690,7 +3739,7 @@ UINT8 FfsEngine::reconstructFile(const QModelIndex& index, const UINT8 revision,
fileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM2; fileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM2;
// Append tail, if needed // Append tail, if needed
if (fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) { if (revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header; UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header;
UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File; UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File;
reconstructed.append(ht).append(ft); reconstructed.append(ht).append(ft);
@ -3732,6 +3781,10 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base,
model->action(index) == Actions::Rebase) { model->action(index) == Actions::Rebase) {
QByteArray header = model->header(index); QByteArray header = model->header(index);
EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*)header.data(); EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*)header.data();
bool extended = false;
if(uint24ToUint32(commonHeader->Size) == 0xFFFFFF) {
extended = true;
}
// Reconstruct section with children // Reconstruct section with children
if (model->rowCount(index)) { if (model->rowCount(index)) {
@ -3832,7 +3885,13 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base,
} }
// Correct section size // Correct section size
uint32ToUint24(header.size() + reconstructed.size(), commonHeader->Size); if (extended) {
EFI_COMMON_SECTION_HEADER2 * extHeader = (EFI_COMMON_SECTION_HEADER2*) commonHeader;
extHeader->ExtendedSize = header.size() + reconstructed.size();
uint32ToUint24(0xFFFFFF, commonHeader->Size);
} else {
uint32ToUint24(header.size() + reconstructed.size(), commonHeader->Size);
}
} }
// Leaf section // Leaf section
else else

View File

@ -70,7 +70,7 @@ public:
UINT8 parseEcRegion(const QByteArray & ec, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseEcRegion(const QByteArray & ec, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex()); UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex());
UINT8 parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 revision = 2, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseSections(const QByteArray & body, const QModelIndex & parent = QModelIndex()); UINT8 parseSections(const QByteArray & body, const QModelIndex & parent = QModelIndex());
UINT8 parseSection(const QByteArray & section, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseSection(const QByteArray & section, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
@ -117,7 +117,6 @@ private:
UINT8 parseDepexSection(const QByteArray & body, QString & parsed); UINT8 parseDepexSection(const QByteArray & body, QString & parsed);
UINT8 findNextVolume(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & nextVolumeOffset); UINT8 findNextVolume(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize); UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize);
UINT8 getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize);
UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize); UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize);
// Reconstruction helpers // Reconstruction helpers

View File

@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) : UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::UEFITool), ui(new Ui::UEFITool),
version(tr("0.21.5")) version(tr("0.22.0"))
{ {
clipboard = QApplication::clipboard(); clipboard = QApplication::clipboard();