mirror of
https://github.com/LongSoft/UEFITool.git
synced 2025-02-13 15:22:42 +08:00
UT 0.20.8
- data after the latest region of Intel image is in tree now - added Intel, Lenovo and Toshiba-specific capsule GUIDs to the list of known GUIDs - fixed bogus "File with invalid size" message while working on almost full volumes - pressing Cancel on "Open in new window" dialog now works as expected Big thanks to Lordkag for spotting most of the issues (#31).
This commit is contained in:
parent
63e5a4dd1c
commit
9c4ddbec62
@ -85,6 +85,7 @@ typedef unsigned int UINTN;
|
||||
#define ERR_INVALID_SYMBOL 40
|
||||
#define ERR_NOTHING_TO_PATCH 41
|
||||
#define ERR_DEPEX_PARSE_FAILED 42
|
||||
#define ERR_TRUNCATED_IMAGE 43
|
||||
#define ERR_NOT_IMPLEMENTED 0xFF
|
||||
|
||||
// UDK porting definitions
|
||||
|
32
ffs.h
32
ffs.h
@ -32,7 +32,7 @@ extern QString sectionTypeToQString(const UINT8 type);
|
||||
//*****************************************************************************
|
||||
// EFI Capsule
|
||||
//*****************************************************************************
|
||||
// Capsule header
|
||||
// Standard EFI Capsule header
|
||||
typedef struct _EFI_CAPSULE_HEADER {
|
||||
EFI_GUID CapsuleGuid;
|
||||
UINT32 HeaderSize;
|
||||
@ -49,16 +49,36 @@ typedef struct _EFI_CAPSULE_HEADER {
|
||||
const QByteArray EFI_CAPSULE_GUID
|
||||
("\xBD\x86\x66\x3B\x76\x0D\x30\x40\xB7\x0E\xB5\x51\x9E\x2F\xC5\xA0", 16);
|
||||
|
||||
// Intel capsule GUID
|
||||
const QByteArray INTEL_CAPSULE_GUID
|
||||
("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16);
|
||||
|
||||
// Lenovo capsule GUID
|
||||
const QByteArray LENOVO_CAPSULE_GUID
|
||||
("\x8B\xA6\x3C\x4A\x23\x77\xFB\x48\x80\x3D\x57\x8C\xC1\xFE\xC4\x4D", 16);
|
||||
|
||||
// Toshiba EFI Capsule header
|
||||
typedef struct _TOSHIBA_CAPSULE_HEADER {
|
||||
EFI_GUID CapsuleGuid;
|
||||
UINT32 HeaderSize;
|
||||
UINT32 FullSize;
|
||||
UINT32 Flags;
|
||||
} TOSHIBA_CAPSULE_HEADER;
|
||||
|
||||
// Toshiba capsule GUID
|
||||
const QByteArray TOSHIBA_CAPSULE_GUID
|
||||
("\x62\x70\xE0\x3B\x51\x1D\xD2\x45\x83\x2B\xF0\x93\x25\x7E\xD4\x61", 16);
|
||||
|
||||
// AMI Aptio extended capsule header
|
||||
typedef struct _APTIO_CAPSULE_HEADER {
|
||||
EFI_CAPSULE_HEADER CapsuleHeader;
|
||||
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of
|
||||
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of
|
||||
// the capsule volume
|
||||
//!TODO: Enable certificate and ROM layout reading
|
||||
//UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume
|
||||
//UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume
|
||||
// that are included in the signature calculation
|
||||
//FW_CERTIFICATE FWCert;
|
||||
//ROM_AREA RomAreaMap[1];
|
||||
//ROM_AREA RomAreaMap[1];
|
||||
} APTIO_CAPSULE_HEADER;
|
||||
|
||||
// AMI Aptio signed extended capsule GUID
|
||||
@ -252,8 +272,8 @@ extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
|
||||
// Integrity check
|
||||
typedef union {
|
||||
struct {
|
||||
UINT8 Header;
|
||||
UINT8 File;
|
||||
UINT8 Header;
|
||||
UINT8 File;
|
||||
} Checksum;
|
||||
UINT16 TailReference; // Revision 1
|
||||
UINT16 Checksum16; // Revision 2
|
||||
|
160
ffsengine.cpp
160
ffsengine.cpp
@ -75,6 +75,7 @@ QString errorMessage(UINT8 errorCode)
|
||||
case ERR_INVALID_SYMBOL: return QObject::tr("Invalid symbol");
|
||||
case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch");
|
||||
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
|
||||
case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated");
|
||||
default: return QObject::tr("Unknown error %1").arg(errorCode);
|
||||
}
|
||||
}
|
||||
@ -146,14 +147,16 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
|
||||
|
||||
// Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER
|
||||
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
|
||||
msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
||||
msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Check buffer for being normal EFI capsule header
|
||||
UINT32 capsuleHeaderSize = 0;
|
||||
QModelIndex index;
|
||||
if (buffer.startsWith(EFI_CAPSULE_GUID)) {
|
||||
if (buffer.startsWith(EFI_CAPSULE_GUID)
|
||||
|| buffer.startsWith(INTEL_CAPSULE_GUID)
|
||||
|| buffer.startsWith(LENOVO_CAPSULE_GUID)) {
|
||||
// Get info
|
||||
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
|
||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||
@ -170,7 +173,24 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
|
||||
}
|
||||
// Check buffer for being Toshiba capsule header
|
||||
else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) {
|
||||
// Get info
|
||||
const TOSHIBA_CAPSULE_HEADER* capsuleHeader = (const TOSHIBA_CAPSULE_HEADER*)buffer.constData();
|
||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||
QString name = tr("UEFI capsule");
|
||||
QString info = tr("Capsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
|
||||
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
||||
.hexarg(buffer.size()).arg(buffer.size())
|
||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)
|
||||
.hexarg(capsuleHeader->FullSize - capsuleHeader->HeaderSize).arg(capsuleHeader->FullSize - capsuleHeader->HeaderSize)
|
||||
.hexarg2(capsuleHeader->Flags, 8);
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
|
||||
}
|
||||
// Check buffer for being extended Aptio signed capsule header
|
||||
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
|
||||
// Get info
|
||||
@ -192,7 +212,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
|
||||
|
||||
|
||||
// Show message about possible Aptio signature break
|
||||
if (signedCapsule) {
|
||||
msg(tr("parseImageFile: Aptio capsule signature may become invalid after image modifications"), index);
|
||||
@ -458,6 +478,34 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
|
||||
return result;
|
||||
}
|
||||
|
||||
// Add the data after the last region as padding
|
||||
UINT32 IntelDataEnd = 0;
|
||||
UINT32 LastRegionOffset = offsets.last();
|
||||
if (LastRegionOffset == gbeBegin)
|
||||
IntelDataEnd = gbeEnd;
|
||||
else if (LastRegionOffset == meBegin)
|
||||
IntelDataEnd = meEnd;
|
||||
else if (LastRegionOffset == biosBegin)
|
||||
IntelDataEnd = biosEnd;
|
||||
else if (LastRegionOffset == pdrBegin)
|
||||
IntelDataEnd = pdrEnd;
|
||||
|
||||
if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated
|
||||
msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged")
|
||||
.hexarg(intelImage.size()).arg(intelImage.size())
|
||||
.hexarg(IntelDataEnd).arg(IntelDataEnd), index);
|
||||
return ERR_TRUNCATED_IMAGE;
|
||||
}
|
||||
else if (IntelDataEnd < (UINT32)intelImage.size()) { // Insert padding
|
||||
QByteArray padding = bios.right(intelImage.size() - IntelDataEnd);
|
||||
// Get info
|
||||
name = tr("Padding");
|
||||
info = tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
// Add tree item
|
||||
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, index);
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -495,7 +543,7 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
|
||||
return ERR_EMPTY_REGION;
|
||||
|
||||
// Get info
|
||||
QString name = tr("ME/TXE region");
|
||||
QString name = tr("ME region");
|
||||
QString info = tr("Full size: %1h (%2)").
|
||||
hexarg(me.size()).arg(me.size());
|
||||
|
||||
@ -536,10 +584,10 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
|
||||
|
||||
// Show messages
|
||||
if (emptyRegion) {
|
||||
msg(tr("parseRegion: ME/TXE region is empty"), index);
|
||||
msg(tr("parseRegion: ME region is empty"), index);
|
||||
}
|
||||
else if (!versionFound) {
|
||||
msg(tr("parseRegion: ME/TXE region version is unknown, it can be damaged"), index);
|
||||
msg(tr("parseRegion: ME region version is unknown, it can be damaged"), index);
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
@ -611,7 +659,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
||||
name = tr("Padding");
|
||||
info = tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
|
||||
|
||||
// Add tree item
|
||||
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
|
||||
}
|
||||
@ -777,7 +825,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
|
||||
// Check for volume structure to be known
|
||||
bool volumeIsUnknown = true;
|
||||
/*UINT8 volumeFfsVersion = 0;*/
|
||||
|
||||
|
||||
// Check for FFS v2 volume
|
||||
if (FFSv2Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) {
|
||||
volumeIsUnknown = false;
|
||||
@ -864,7 +912,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
|
||||
if (msgInvalidChecksum) {
|
||||
msg(tr("parseVolume: volume header checksum is invalid"), index);
|
||||
}
|
||||
|
||||
|
||||
// Search for and parse all files
|
||||
UINT32 fileOffset = headerSize;
|
||||
UINT32 fileSize;
|
||||
@ -874,6 +922,22 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
|
||||
bool msgUnalignedFile = false;
|
||||
bool msgDuplicateGuid = false;
|
||||
|
||||
// Check if it's possibly the latest file in the volume
|
||||
if (volumeSize - fileOffset < sizeof(EFI_FFS_FILE_HEADER)) {
|
||||
// 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, mode);
|
||||
}
|
||||
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, mode);
|
||||
msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex);
|
||||
}
|
||||
// Exit from loop
|
||||
break;
|
||||
}
|
||||
|
||||
result = getFileSize(volume, fileOffset, fileSize);
|
||||
if (result)
|
||||
return result;
|
||||
@ -907,7 +971,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
|
||||
i = ALIGN8(i) - 8;
|
||||
|
||||
// Add all bytes before as free space...
|
||||
if (i > 0) {
|
||||
if (i > 0) {
|
||||
QByteArray free = freeSpace.left(i);
|
||||
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode);
|
||||
}
|
||||
@ -1079,7 +1143,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
|
||||
QString info;
|
||||
if (fileHeader->Type != EFI_FV_FILETYPE_PAD)
|
||||
name = guidToQString(fileHeader->Name);
|
||||
else
|
||||
else
|
||||
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")
|
||||
@ -1103,7 +1167,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
|
||||
msg(tr("parseFile: invalid tail value"), index);
|
||||
if (msgInvalidType)
|
||||
msg(tr("parseFile: unknown file type %1h").arg(fileHeader->Type, 2), index);
|
||||
|
||||
|
||||
// No parsing needed
|
||||
if (!parseCurrentFile)
|
||||
return ERR_SUCCESS;
|
||||
@ -1126,10 +1190,10 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
|
||||
// ... and all bytes after as a padding
|
||||
QByteArray padding = body.mid(i);
|
||||
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode);
|
||||
|
||||
|
||||
// Show message
|
||||
msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), dataIndex);
|
||||
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1211,7 +1275,7 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed)
|
||||
|
||||
const EFI_GUID * guid;
|
||||
const UINT8* current = (const UINT8*)body.constData();
|
||||
|
||||
|
||||
// Special cases of first opcode
|
||||
switch (*current) {
|
||||
case EFI_DEP_BEFORE:
|
||||
@ -1241,7 +1305,7 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed)
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse the rest of depex
|
||||
// Parse the rest of depex
|
||||
while (current - (const UINT8*)body.constData() < body.size()) {
|
||||
switch (*current) {
|
||||
case EFI_DEP_BEFORE:
|
||||
@ -1287,9 +1351,9 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed)
|
||||
return ERR_DEPEX_PARSE_FAILED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ERR_DEPEX_PARSE_FAILED;
|
||||
break;
|
||||
default:
|
||||
return ERR_DEPEX_PARSE_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1379,11 +1443,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
|
||||
// Tiano compressed section
|
||||
if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
|
||||
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
||||
|
||||
|
||||
result = decompress(body, EFI_STANDARD_COMPRESSION, processed, &algorithm);
|
||||
if (result)
|
||||
parseCurrentSection = false;
|
||||
|
||||
|
||||
if (algorithm == COMPRESSION_ALGORITHM_TIANO) {
|
||||
info += tr("\nCompression type: Tiano");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
@ -1392,17 +1456,17 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
|
||||
info += tr("\nCompression type: EFI 1.1");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else
|
||||
else
|
||||
info += tr("\nCompression type: unknown");
|
||||
}
|
||||
// LZMA compressed section
|
||||
else if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) {
|
||||
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
||||
|
||||
|
||||
result = decompress(body, EFI_CUSTOMIZED_COMPRESSION, processed, &algorithm);
|
||||
if (result)
|
||||
parseCurrentSection = false;
|
||||
|
||||
|
||||
if (algorithm == COMPRESSION_ALGORITHM_LZMA) {
|
||||
info += tr("\nCompression type: LZMA");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
@ -1570,7 +1634,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
|
||||
if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
|
||||
info += tr("\nSignature: %1h, invalid").hexarg2(teHeader->Signature, 4);
|
||||
msgInvalidSignature = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
info += tr("\nSignature: %1h\nMachine type: %2\nNumber of sections: %3\nSubsystem: %4h\nStrippedSize: %5h (%6)\nBaseOfCode: %7h\nRelativeEntryPoint: %8h\nImageBase: %9h\nEntryPoint: %10h")
|
||||
.hexarg2(teHeader->Signature, 4)
|
||||
@ -1833,7 +1897,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
|
||||
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
|
||||
|
||||
// Parse section body as BIOS space
|
||||
if (!parsed) {
|
||||
if (!parsed) {
|
||||
result = parseBios(body, index);
|
||||
if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) {
|
||||
msg(tr("parseSection: parsing raw section as BIOS failed with error \"%1\"").arg(errorMessage(result)), index);
|
||||
@ -1922,7 +1986,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
|
||||
}
|
||||
else if (type == Types::Volume) {
|
||||
QByteArray volume;
|
||||
if (header.isEmpty()) // Whole volume
|
||||
if (header.isEmpty()) // Whole volume
|
||||
volume.append(body);
|
||||
else { // Body only
|
||||
volume.append(model->header(index)).append(body);
|
||||
@ -1936,7 +2000,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
|
||||
result = parseVolume(volume, fileIndex, index, mode);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
||||
// Set action
|
||||
model->setAction(fileIndex, action);
|
||||
}
|
||||
@ -1954,7 +2018,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
|
||||
QByteArray newHeader = header;
|
||||
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)newHeader.data();
|
||||
|
||||
|
||||
|
||||
// Correct file size
|
||||
UINT8 tailSize = fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT ? sizeof(UINT16) : 0;
|
||||
uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + body.size() + tailSize, fileHeader->Size);
|
||||
@ -2478,7 +2542,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
||||
return ERR_STANDARD_COMPRESSION_FAILED;
|
||||
}
|
||||
compressedData = QByteArray((const char*)compressed, compressedSize);
|
||||
|
||||
|
||||
// Check that compressed data can be decompressed normally
|
||||
QByteArray decompressed;
|
||||
if (decompress(compressedData, EFI_STANDARD_COMPRESSION, decompressed, NULL) == ERR_SUCCESS
|
||||
@ -2498,7 +2562,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
||||
return ERR_STANDARD_COMPRESSION_FAILED;
|
||||
}
|
||||
compressedData = QByteArray((const char*)compressed, compressedSize);
|
||||
|
||||
|
||||
// New functions will be trusted here, because another check will reduce performance
|
||||
delete[] compressed;
|
||||
return ERR_SUCCESS;
|
||||
@ -2657,12 +2721,20 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec
|
||||
char empty = '\xFF';
|
||||
for (int i = 1; i < model->rowCount(index); i++) {
|
||||
QByteArray region;
|
||||
|
||||
// Padding after the end of all Intel regions
|
||||
if (model->type(index.child(i, 0)) == Types::Padding) {
|
||||
region = model->body(index.child(i, 0));
|
||||
reconstructed.append(region);
|
||||
offset += region.size();
|
||||
continue;
|
||||
}
|
||||
|
||||
result = reconstructRegion(index.child(i, 0), region);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
UINT8 type = model->subtype(index.child(i, 0));
|
||||
switch (type)
|
||||
switch (model->subtype(index.child(i, 0)))
|
||||
{
|
||||
case Subtypes::GbeRegion:
|
||||
gbe = region;
|
||||
@ -2761,7 +2833,7 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst
|
||||
if (reconstructed.size() > model->body(index).size()) {
|
||||
msg(tr("reconstructRegion: reconstructed region size %1h (%2) is bigger then original %3h (%4)")
|
||||
.hexarg(reconstructed.size()).arg(reconstructed.size())
|
||||
.hexarg(model->body(index).size()).arg(reconstructed.size()),
|
||||
.hexarg(model->body(index).size()).arg(reconstructed.size()),
|
||||
index);
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
@ -2799,7 +2871,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
|
||||
reconstructed.clear();
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
else if (model->action(index) == Actions::Replace ||
|
||||
else if (model->action(index) == Actions::Replace ||
|
||||
model->action(index) == Actions::Rebuild) {
|
||||
QByteArray header = model->header(index);
|
||||
QByteArray body = model->body(index);
|
||||
@ -2811,7 +2883,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
|
||||
|
||||
// Get volume size
|
||||
UINT32 volumeSize = header.size() + body.size();
|
||||
|
||||
|
||||
// Reconstruct volume body
|
||||
UINT32 freeSpaceOffset = 0;
|
||||
if (model->rowCount(index)) {
|
||||
@ -2926,7 +2998,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
|
||||
// Pad file
|
||||
if (fileHeader->Type == EFI_FV_FILETYPE_PAD) {
|
||||
padFileGuid = file.left(sizeof(EFI_GUID));
|
||||
|
||||
|
||||
// Parse non-empty pad file
|
||||
if (model->rowCount(index.child(i, 0))) {
|
||||
//TODO: handle it
|
||||
@ -2981,7 +3053,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
|
||||
// Get non-UEFI data and it's offset
|
||||
nonUefiData = model->body(index.child(i + 1, 0));
|
||||
nonUefiDataOffset = body.size() - nonUefiData.size();
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3133,7 +3205,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
|
||||
volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -3435,7 +3507,7 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base,
|
||||
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)model->body(index).constData();
|
||||
teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
|
||||
}*/
|
||||
|
||||
|
||||
if (base) {
|
||||
result = rebase(reconstructed, base - teFixup + header.size());
|
||||
if (result) {
|
||||
@ -3966,7 +4038,7 @@ UINT8 FfsEngine::getBase(const QByteArray& file, UINT32& base)
|
||||
// Populate TE header
|
||||
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)file.constData();
|
||||
//!TODO: add handling
|
||||
base = teHeader->ImageBase;
|
||||
base = teHeader->ImageBase;
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
@ -4041,10 +4113,10 @@ UINT8 FfsEngine::recursiveDump(const QModelIndex & index, const QString & path,
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
QDir dir;
|
||||
if (guid.isEmpty() ||
|
||||
if (guid.isEmpty() ||
|
||||
guidToQString(*(const EFI_GUID*)model->header(index).constData()) == guid ||
|
||||
guidToQString(*(const EFI_GUID*)model->header(model->findParentOfType(index, Types::File)).constData()) == guid) {
|
||||
|
||||
|
||||
if (dir.cd(path))
|
||||
return ERR_DIR_ALREADY_EXIST;
|
||||
|
||||
@ -4079,7 +4151,7 @@ UINT8 FfsEngine::recursiveDump(const QModelIndex & index, const QString & path,
|
||||
file.write(info.toLatin1());
|
||||
file.close();
|
||||
dumped = true;
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 result;
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
|
12
types.cpp
12
types.cpp
@ -24,7 +24,7 @@ QString regionTypeToQString(const UINT8 type)
|
||||
case Subtypes::GbeRegion:
|
||||
return QObject::tr("GbE");
|
||||
case Subtypes::MeRegion:
|
||||
return QObject::tr("ME/TXE");
|
||||
return QObject::tr("ME");
|
||||
case Subtypes::BiosRegion:
|
||||
return QObject::tr("BIOS");
|
||||
case Subtypes::PdrRegion:
|
||||
@ -80,7 +80,7 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
|
||||
return QObject::tr("Non-empty");
|
||||
else
|
||||
return QObject::tr("Unknown subtype");
|
||||
case Types::Volume:
|
||||
case Types::Volume:
|
||||
if (subtype == Subtypes::UnknownVolume)
|
||||
return QObject::tr("Unknown");
|
||||
else if (subtype == Subtypes::Ffs2Volume)
|
||||
@ -89,14 +89,16 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
|
||||
return QObject::tr("FFSv3");
|
||||
else
|
||||
return QObject::tr("Unknown subtype");
|
||||
case Types::Capsule:
|
||||
case Types::Capsule:
|
||||
if (subtype == Subtypes::AptioSignedCapsule)
|
||||
return QObject::tr("Aptio signed");
|
||||
else if (subtype == Subtypes::AptioUnsignedCapsule)
|
||||
return QObject::tr("Aptio unsigned");
|
||||
else if (subtype == Subtypes::UefiCapsule)
|
||||
return QObject::tr("UEFI 2.0 ");
|
||||
else
|
||||
return QObject::tr("UEFI 2.0");
|
||||
else if (subtype == Subtypes::ToshibaCapsule)
|
||||
return QObject::tr("Toshiba");
|
||||
else
|
||||
return QObject::tr("Unknown subtype");
|
||||
case Types::Region:
|
||||
return regionTypeToQString(subtype);
|
||||
|
3
types.h
3
types.h
@ -54,7 +54,8 @@ namespace Subtypes {
|
||||
enum CapsuleSubtypes {
|
||||
AptioSignedCapsule = 80,
|
||||
AptioUnsignedCapsule,
|
||||
UefiCapsule
|
||||
UefiCapsule,
|
||||
ToshibaCapsule
|
||||
};
|
||||
|
||||
enum VolumeSubtypes {
|
||||
|
12
uefitool.cpp
12
uefitool.cpp
@ -16,8 +16,8 @@
|
||||
|
||||
UEFITool::UEFITool(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::UEFITool),
|
||||
version(tr("0.20.7"))
|
||||
ui(new Ui::UEFITool),
|
||||
version(tr("0.20.8"))
|
||||
{
|
||||
clipboard = QApplication::clipboard();
|
||||
|
||||
@ -85,8 +85,8 @@ UEFITool::~UEFITool()
|
||||
}
|
||||
|
||||
void UEFITool::setProgramPath(QString path)
|
||||
{
|
||||
currentProgramPath = path;
|
||||
{
|
||||
currentProgramPath = path;
|
||||
};
|
||||
|
||||
void UEFITool::init()
|
||||
@ -455,7 +455,7 @@ void UEFITool::extract(const UINT8 mode)
|
||||
case Types::Capsule:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), currentDir, "Image files (*.rom *.bin);;All files (*)");
|
||||
break;
|
||||
case Types::Volume:
|
||||
case Types::Volume:
|
||||
path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), currentDir, "Volume body files (*.vbd *.bin);;All files (*)");
|
||||
break;
|
||||
case Types::File: {
|
||||
@ -567,6 +567,8 @@ void UEFITool::openImageFile()
|
||||
void UEFITool::openImageFileInNewWindow()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)");
|
||||
if (path.trimmed().isEmpty())
|
||||
return;
|
||||
QProcess::startDetached(currentProgramPath, QStringList(path));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user