From e5d94b64791094df905321038bb0fd280f0eb0a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Wed, 26 Feb 2014 09:33:38 +0100 Subject: [PATCH] Version 0.17.4 - solved a bug in wrong volume size calculation in rare cases - added diagnostic message if FvLength and size calculated using BlockMap are different - solved a bug that lead to unneeded PEI files relocation - rebuild action on volume will now relocate PEI files in it --- ffsengine.cpp | 70 +++++++++++++++++++++++++++++++++------------------ ffsengine.h | 2 +- uefitool.ui | 2 +- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/ffsengine.cpp b/ffsengine.cpp index 908a032..1cfe4f8 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -623,11 +623,11 @@ UINT8 FfsEngine::findNextVolume(const QByteArray & bios, UINT32 volumeOffset, UI return ERR_VOLUMES_NOT_FOUND; } - nextVolumeOffset = nextIndex - EFI_FV_SIGNATURE_OFFSET; + nextVolumeOffset = nextIndex - EFI_FV_SIGNATURE_OFFSET; return ERR_SUCCESS; } -UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize, bool fromHeader) +UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UINT32 & volumeSize) { // Populate volume header EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) (bios.constData() + volumeOffset); @@ -636,22 +636,29 @@ UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UIN if (QByteArray((const char*) &volumeHeader->Signature, sizeof(volumeHeader->Signature)) != EFI_FV_SIGNATURE) return ERR_INVALID_VOLUME; - if (fromHeader) { - // Use header field - volumeSize = volumeHeader->FvLength; - } - else { - // Use BlockMap - EFI_FV_BLOCK_MAP_ENTRY* entry = (EFI_FV_BLOCK_MAP_ENTRY*)(bios.constData() + volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER)); - volumeSize = 0; - while (entry->NumBlocks != 0 && entry->Length != 0) { - if ((void*)entry > bios.constData() + bios.size()) - return ERR_INVALID_VOLUME; + // Calculate volume size using BlockMap + EFI_FV_BLOCK_MAP_ENTRY* entry = (EFI_FV_BLOCK_MAP_ENTRY*)(bios.constData() + volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER)); + UINT32 bmVolumeSize = 0; + while (entry->NumBlocks != 0 && entry->Length != 0) { + if ((void*)entry > bios.constData() + bios.size()) + return ERR_INVALID_VOLUME; - volumeSize += entry->NumBlocks * entry->Length; - entry += 1; - } + bmVolumeSize += entry->NumBlocks * entry->Length; + entry += 1; } + + // Check calculated and stored volume sizes to be the same + if (volumeHeader->FvLength != bmVolumeSize) { + msg(tr("getVolumeSize: %1, volume size in header (%2) differs from calculated using BlockMap (%3). Smaller value is used.") + .arg(guidToQString(volumeHeader->FileSystemGuid)) + .arg(volumeHeader->FvLength, 8, 16, QChar('0')) + .arg(bmVolumeSize, 8, 16, QChar('0'))); + + // Use smaller value as volume size + volumeSize = volumeHeader->FvLength < bmVolumeSize ? volumeHeader->FvLength : bmVolumeSize; + } + else + volumeSize = bmVolumeSize; return ERR_SUCCESS; } @@ -704,7 +711,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co UINT8 result; UINT32 volumeSize; - result = getVolumeSize(volume, 0, volumeSize, false); + result = getVolumeSize(volume, 0, volumeSize); if (result) return result; @@ -1601,7 +1608,9 @@ UINT8 FfsEngine::remove(const QModelIndex & index) QModelIndex fileIndex; - if (model->type(index) == File) + if (model->type(index) == Volume && model->rowCount(index) > 0) + fileIndex = index.child(0, 0); + else if(model->type(index) == File) fileIndex = index; else if (model->type(index) == Section) fileIndex = model->findParentOfType(index, File); @@ -1624,7 +1633,9 @@ UINT8 FfsEngine::rebuild(const QModelIndex & index) QModelIndex fileIndex; - if (model->type(index) == File) + if (model->type(index) == Volume && model->rowCount(index) > 0) + fileIndex = index.child(0, 0); + else if (model->type(index) == File) fileIndex = index; else if (model->type(index) == Section) fileIndex = model->findParentOfType(index, File); @@ -2019,7 +2030,7 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst return ERR_NOT_IMPLEMENTED; } -UINT8 FfsEngine::reconstructVolume(const QModelIndex& index, QByteArray& reconstructed) +UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & reconstructed) { if (!index.isValid()) return ERR_SUCCESS; @@ -2075,8 +2086,20 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex& index, QByteArray& reconst break; } } + + // Determine if volume is inside compressed item + if (!baseFound) { + // Iterate up to the root, checking for compression type to be other then none + for (QModelIndex parentIndex = index.parent(); model->type(parentIndex) != Root; parentIndex = parentIndex.parent()) + if (model->compression(parentIndex) != COMPRESSION_ALGORITHM_NONE) { + // No rebase needed for compressed PEI files + baseFound = true; + volumeBase = 0; + break; + } + } - // VTF not found + // Find volume base address using first PEI file in it if (!baseFound) { // Search for first PEI-file and use it as base source UINT32 fileOffset = header.size(); @@ -2103,13 +2126,12 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex& index, QByteArray& reconst // Calculate volume base volumeBase = imagebase - relbase; baseFound = true; + goto out; } - goto out; } sectionOffset += model->header(peiFile.child(j,0)).size() + model->body(peiFile.child(j,0)).size(); sectionOffset = ALIGN4(sectionOffset); } - } fileOffset += model->header(index.child(i, 0)).size() + model->body(index.child(i, 0)).size() + model->tail(index.child(i, 0)).size(); fileOffset = ALIGN8(fileOffset); @@ -2572,8 +2594,6 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base, msg(tr("reconstructSection: can't get entry point of PEI core"), index); } } - else - msg(tr("reconstructSection: volume base is unknown, section can't be rebased"), index); } // Reconstruction successful diff --git a/ffsengine.h b/ffsengine.h index 4ae06df..92a3ba3 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -93,7 +93,7 @@ private: // Parsing helpers UINT8 findNextVolume(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & nextVolumeOffset); - UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, bool fromHeader = true); + UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize); UINT8 getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize); UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize); diff --git a/uefitool.ui b/uefitool.ui index ef5ede9..f42fd76 100644 --- a/uefitool.ui +++ b/uefitool.ui @@ -20,7 +20,7 @@ true - UEFITool 0.17.3 + UEFITool 0.17.4