Version 0.17.0

- solved a big in extracting tailed file
- added "Unknown" volume type
- files can't be inserted to unknown volumes
- sections can be inserted into encapsulation sections
- regions (except Descriptor) can be replaced
- Rebuild action removed from all types of items but Volume, File and
Section, it did nothing for them
- Descriptor region info now shows region access map and BIOS access
table
This commit is contained in:
Nikolaj Schlej 2014-01-28 17:42:18 +01:00
parent a4a40ec329
commit 66dc4bb6e3
6 changed files with 127 additions and 73 deletions

View file

@ -152,7 +152,8 @@ enum CapsuleSubtypes {
};
enum VolumeSubtypes {
BootVolume = 90
BootVolume = 90,
UnknownVolume
};
enum RegionSubtypes {

View file

@ -299,7 +299,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
// Region access settings
info += tr("\nRegion access settings:");
info += tr("\nBIOS %1%2 ME %2%3 GbE %4%5")
info += tr("\nBIOS:%1%2 ME:%2%3 GbE:%4%5")
.arg(masterSection->BiosRead, 2, 16, QChar('0'))
.arg(masterSection->BiosWrite, 2, 16, QChar('0'))
.arg(masterSection->MeRead, 2, 16, QChar('0'))
@ -315,20 +315,19 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ");
info += tr("\nBIOS Yes Yes");
info += tr("\nME %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ");
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ");
info += tr("\nGbE %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ");
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ");
info += tr("\nPDR %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ");
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ");
// VSCC table
// Add descriptor tree item
model->addItem(Region, DescriptorRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), body, QByteArray(), index);
// Sort regions in ascending order
qSort(offsets);
@ -362,7 +361,7 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
return ERR_SUCCESS;
}
UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, QModelIndex & index, const QModelIndex & parent)
UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, QModelIndex & index, const QModelIndex & parent, const UINT8 mode)
{
if (gbe.isEmpty())
return ERR_EMPTY_REGION;
@ -383,12 +382,12 @@ UINT8 FfsEngine::parseGbeRegion(const QByteArray & gbe, QModelIndex & index, con
.arg(version->minor);
// Add tree item
index = model->addItem( Region, GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, QByteArray(), parent);
index = model->addItem(Region, GbeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), gbe, QByteArray(), parent, mode);
return ERR_SUCCESS;
}
UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent)
UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent, const UINT8 mode)
{
if (me.isEmpty())
return ERR_EMPTY_REGION;
@ -413,12 +412,12 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
}
// Add tree item
index = model->addItem( Region, MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, QByteArray(), parent);
index = model->addItem(Region, MeRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), me, QByteArray(), parent, mode);
return ERR_SUCCESS;
}
UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent)
UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent, const UINT8 mode)
{
if (pdr.isEmpty())
return ERR_EMPTY_REGION;
@ -429,12 +428,12 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con
arg(pdr.size(), 8, 16, QChar('0'));
// Add tree item
index = model->addItem( Region, PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent);
index = model->addItem(Region, PdrRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), pdr, QByteArray(), parent, mode);
return ERR_SUCCESS;
}
UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent)
UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode)
{
if (bios.isEmpty())
return ERR_EMPTY_REGION;
@ -445,7 +444,7 @@ UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, c
arg(bios.size(), 8, 16, QChar('0'));
// Add tree item
index = model->addItem( Region, BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent);
index = model->addItem(Region, BiosRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), bios, QByteArray(), parent, mode);
return parseBios(bios, index);
}
@ -459,7 +458,6 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
if (result)
return result;
// First volume is not at the beginning of BIOS space
QString name;
QString info;
@ -674,7 +672,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
}
// Other GUID
else {
msg(tr("parseBios: Unknown file system (%1)").arg(guidToQString(volumeHeader->FileSystemGuid)), parent);
msg(tr("parseVolume: Unknown file system (%1)").arg(guidToQString(volumeHeader->FileSystemGuid)), parent);
parseCurrentVolume = false;
}
@ -684,7 +682,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Check header checksum by recalculating it
if (calculateChecksum16((UINT16*) volumeHeader, volumeHeader->HeaderLength)) {
msg(tr("parseBios: Volume header checksum is invalid"), parent);
msg(tr("parseVolume: Volume header checksum is invalid"), parent);
}
// Check for presence of extended header, only if header revision is greater then 1
@ -706,7 +704,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Check reported size
if (volumeSize != volumeHeader->FvLength) {
msg(tr("%1: volume size stored in header %2 differs from calculated size %3")
msg(tr("parseVolume: %1: volume size stored in header %2 differs from calculated size %3")
.arg(guidToQString(volumeHeader->FileSystemGuid))
.arg(volumeHeader->FvLength, 8, 16, QChar('0'))
.arg(volumeSize, 8, 16, QChar('0')), parent);
@ -723,11 +721,15 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Add tree item
QByteArray header = volume.left(headerSize);
QByteArray body = volume.mid(headerSize, volumeSize - headerSize);
index = model->addItem( Volume, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
// Do not parse volumes with unknown FS
if (!parseCurrentVolume)
if (!parseCurrentVolume) {
index = model->addItem(Volume, UnknownVolume, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
return ERR_SUCCESS;
}
else
index = model->addItem(Volume, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
// Search for and parse all files
UINT32 fileOffset = headerSize;
@ -1228,7 +1230,32 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
parent = index;
// Create item
if (type == File) {
if (type == Region) {
UINT8 subtype = model->subtype(index);
switch (subtype) {
case BiosRegion:
result = parseBiosRegion(body, fileIndex, index, mode);
break;
case MeRegion:
result = parseMeRegion(body, fileIndex, index, mode);
break;
case GbeRegion:
result = parseGbeRegion(body, fileIndex, index, mode);
break;
case PdrRegion:
result = parsePdrRegion(body, fileIndex, index, mode);
break;
default:
return ERR_NOT_IMPLEMENTED;
}
if (result)
return result;
// Set action
model->setAction(fileIndex, action);
}
else if (type == File) {
if (model->type(parent) != Volume)
return ERR_INVALID_FILE;
@ -1263,8 +1290,11 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
created.append(body);
// Append tail, if needed
if (tailSize)
created.append(~fileHeader->IntegrityCheck.TailReference);
if (tailSize) {
UINT8 ht = ~fileHeader->IntegrityCheck.Checksum.Header;
UINT8 ft = ~fileHeader->IntegrityCheck.Checksum.File;
created.append(ht).append(ft);
}
// Set file state
UINT8 state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | EFI_FILE_HEADER_CONSTRUCTION;
@ -1282,8 +1312,11 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
// Set action
model->setAction(fileIndex, action);
// Rebase all PEI-files that follow
rebasePeiFiles(fileIndex);
}
else if (type == Section) {
else if (type == Section) {
if (model->type(parent) != File && model->type(parent) != Section)
return ERR_INVALID_SECTION;
@ -1380,16 +1413,13 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
// Find parent file for rebase
fileIndex = model->findParentOfType(parent, File);
}
// Rebase all PEI-files that follow
rebasePeiFiles(fileIndex);
}
else
return ERR_NOT_IMPLEMENTED;
if (!fileIndex.isValid())
return ERR_INVALID_FILE;
// Rebase all PEI-files that follow
rebasePeiFiles(fileIndex);
return ERR_SUCCESS;
}
@ -1428,12 +1458,17 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
// Determine type of item to insert
UINT8 type;
UINT32 headerSize;
if (model->type(parent) == Volume) {
type = File;
if (model->type(parent) == Volume) {
type = File;
headerSize = sizeof(EFI_FFS_FILE_HEADER);
}
else if (model->type(parent) == File) {
type = Section;
else if (model->type(parent) == File) {
type = Section;
EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*) object.constData();
headerSize = sizeOfSectionHeaderOfType(commonHeader->Type);
}
else if (model->type(parent) == Section) {
type = Section;
EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*) object.constData();
headerSize = sizeOfSectionHeaderOfType(commonHeader->Type);
}
@ -1451,24 +1486,30 @@ UINT8 FfsEngine::replace(const QModelIndex & index, const QByteArray & object, c
// Determine type of item to replace
UINT32 headerSize;
UINT8 result;
if (model->type(index) == File) {
if (mode == REPLACE_MODE_AS_IS) {
headerSize = sizeof(EFI_FFS_FILE_HEADER);
result = create(index, File, object.left(headerSize), object.right(object.size() - headerSize), CREATE_MODE_AFTER, Replace);
}
else if (mode == REPLACE_MODE_BODY)
result = create(index, File, model->header(index), object, CREATE_MODE_AFTER, Replace);
if (model->type(index) == Region) {
if (mode == REPLACE_MODE_AS_IS)
result = create(index, Region, QByteArray(), object, CREATE_MODE_AFTER, Replace);
else
return ERR_NOT_IMPLEMENTED;
}
else if (model->type(index) == Section) {
else if (model->type(index) == File) {
if (mode == REPLACE_MODE_AS_IS) {
headerSize = sizeof(EFI_FFS_FILE_HEADER);
result = create(index, File, object.left(headerSize), object.right(object.size() - headerSize), CREATE_MODE_AFTER, Replace);
}
else if (mode == REPLACE_MODE_BODY)
result = create(index, File, model->header(index), object, CREATE_MODE_AFTER, Replace);
else
return ERR_NOT_IMPLEMENTED;
}
else if (model->type(index) == Section) {
if (mode == REPLACE_MODE_AS_IS) {
EFI_COMMON_SECTION_HEADER* commonHeader = (EFI_COMMON_SECTION_HEADER*) object.constData();
headerSize = sizeOfSectionHeaderOfType(commonHeader->Type);
result = create(index, Section, object.left(headerSize), object.right(object.size() - headerSize), CREATE_MODE_AFTER, Replace);
result = create(index, Section, object.left(headerSize), object.right(object.size() - headerSize), CREATE_MODE_AFTER, Replace);
}
else if (mode == REPLACE_MODE_BODY) {
result = create(index, Section, model->header(index), object, CREATE_MODE_AFTER, Replace, model->compression(index));
result = create(index, Section, model->header(index), object, CREATE_MODE_AFTER, Replace, model->compression(index));
}
else
return ERR_NOT_IMPLEMENTED;
@ -1923,8 +1964,12 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst
reconstructed = model->header(index).append(model->body(index)).append(model->tail(index));
return ERR_SUCCESS;
}
else if (model->action(index) == Rebuild) {
else if (model->action(index) == Remove) {
reconstructed.clear();
return ERR_SUCCESS;
}
else if (model->action(index) == Rebuild ||
model->action(index) == Replace) {
if (model->rowCount(index)) {
reconstructed.clear();
// Reconstruct children

View file

@ -46,10 +46,10 @@ public:
// Firmware image parsing
UINT8 parseImageFile(const QByteArray & buffer);
UINT8 parseIntelImage(const QByteArray & intelImage, QModelIndex & index, const QModelIndex & parent = QModelIndex());
UINT8 parseGbeRegion(const QByteArray & gbe, QModelIndex & index, const QModelIndex & parent);
UINT8 parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent);
UINT8 parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent);
UINT8 parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent);
UINT8 parseGbeRegion(const QByteArray & gbe, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
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 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);

View file

@ -56,11 +56,13 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
case Volume:
if (subtype == BootVolume)
return QObject::tr("Boot");
else if (subtype == UnknownVolume)
return QObject::tr("Unknown");
else
return "";
case Capsule:
if (subtype == AptioCapsule)
return QObject::tr("Aptio extended");
return QObject::tr("AMI Aptio");
else if (subtype == UefiCapsule)
return QObject::tr("UEFI 2.0");
else

View file

@ -109,13 +109,15 @@ void UEFITool::populateUi(const QModelIndex &current)
// Enable actions
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
ui->actionRebuild->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
ui->actionRebuild->setEnabled(type == Volume || type == File || type == Section);
ui->actionExtractBody->setDisabled(model->hasEmptyHeader(current));
ui->actionRemove->setEnabled(type == Volume || type == File || type == Section);
ui->actionInsertInto->setEnabled(type == Volume || (type == File && subtype != EFI_FV_FILETYPE_ALL && subtype != EFI_FV_FILETYPE_RAW && subtype != EFI_FV_FILETYPE_PAD));
ui->actionInsertInto->setEnabled((type == Volume && subtype != UnknownVolume) ||
(type == File && subtype != EFI_FV_FILETYPE_ALL && subtype != EFI_FV_FILETYPE_RAW && subtype != EFI_FV_FILETYPE_PAD) ||
(type == Section && (subtype == EFI_SECTION_COMPRESSION || subtype == EFI_SECTION_GUID_DEFINED || subtype == EFI_SECTION_DISPOSABLE)));
ui->actionInsertBefore->setEnabled(type == File || type == Section);
ui->actionInsertAfter->setEnabled(type == File || type == Section);
ui->actionReplace->setEnabled(type == File || type == Section);
ui->actionReplace->setEnabled((type == Region && subtype != DescriptorRegion) || type == File || type == Section);
ui->actionReplaceBody->setEnabled(type == File || type == Section);
}
@ -222,7 +224,7 @@ void UEFITool::insert(const UINT8 mode)
UINT8 result = ffsEngine->insert(index, buffer, mode);
if (result)
QMessageBox::critical(this, tr("Insertion failed"), tr("Error code: %d").arg(result), QMessageBox::Ok);
QMessageBox::critical(this, tr("Insertion failed"), tr("Error code: %1").arg(result), QMessageBox::Ok);
else
ui->actionSaveImageFile->setEnabled(true);
}
@ -260,7 +262,14 @@ void UEFITool::replace(const UINT8 mode)
TreeModel* model = ffsEngine->treeModel();
QString path;
if (model->type(index) == File) {
if (model->type(index) == Region) {
if (mode == REPLACE_MODE_AS_IS) {
path = QFileDialog::getOpenFileName(this, tr("Select region file to replace selected object"), ".", "Region files (*.rgn *.bin);;All files (*.*)");
}
else
return;
}
else if (model->type(index) == File) {
if (mode == REPLACE_MODE_AS_IS) {
path = QFileDialog::getOpenFileName(this, tr("Select FFS file to replace selected object"),".","FFS files (*.ffs *.bin);;All files (*.*)");
}
@ -314,7 +323,7 @@ void UEFITool::replace(const UINT8 mode)
UINT8 result = ffsEngine->replace(index, buffer, mode);
if (result)
QMessageBox::critical(this, tr("Replacing failed"), tr("Error code: %d").arg(result), QMessageBox::Ok);
QMessageBox::critical(this, tr("Replacing failed"), tr("Error code: %1").arg(result), QMessageBox::Ok);
else
ui->actionSaveImageFile->setEnabled(true);
}
@ -399,7 +408,7 @@ void UEFITool::extract(const UINT8 mode)
QByteArray extracted;
UINT8 result = ffsEngine->extract(index, extracted, mode);
if (result) {
QMessageBox::critical(this, tr("Extraction failed"), tr("Error code: %d").arg(result), QMessageBox::Ok);
QMessageBox::critical(this, tr("Extraction failed"), tr("Error code: %1").arg(result), QMessageBox::Ok);
return;
}
@ -441,13 +450,14 @@ void UEFITool::saveImageFile()
{
QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"),".","BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.efi);;All files (*.*)");
if (path.isEmpty())
return;
QByteArray reconstructed;
UINT8 result = ffsEngine->reconstructImageFile(reconstructed);
showMessages();
if (result) {
QMessageBox::critical(this, tr("Image reconstruction failed"), tr("Error code: %d").arg(result), QMessageBox::Ok);
QMessageBox::critical(this, tr("Image reconstruction failed"), tr("Error code: %1").arg(result), QMessageBox::Ok);
return;
}
@ -495,7 +505,7 @@ void UEFITool::openImageFile(QString path)
UINT8 result = ffsEngine->parseImageFile(buffer);
showMessages();
if (result)
QMessageBox::critical(this, tr("Image parsing failed"), tr("Error code: %d").arg(result), QMessageBox::Ok);
QMessageBox::critical(this, tr("Image parsing failed"), tr("Error code: %1").arg(result), QMessageBox::Ok);
else
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));

View file

@ -20,7 +20,7 @@
<bool>true</bool>
</property>
<property name="windowTitle">
<string>UEFITool 0.16.6</string>
<string>UEFITool 0.17.0</string>
</property>
<widget class="QWidget" name="centralWidget">
<property name="sizePolicy">
@ -226,16 +226,12 @@
</property>
<addaction name="actionExtract"/>
<addaction name="actionExtractBody"/>
<addaction name="separator"/>
<addaction name="actionRebuild"/>
</widget>
<widget class="QMenu" name="menuImageActions">
<property name="title">
<string>&amp;Image</string>
</property>
<addaction name="actionExtract"/>
<addaction name="separator"/>
<addaction name="actionRebuild"/>
</widget>
<widget class="QMenu" name="menuRegionActions">
<property name="title">
@ -243,7 +239,7 @@
</property>
<addaction name="actionExtract"/>
<addaction name="separator"/>
<addaction name="actionRebuild"/>
<addaction name="actionReplace"/>
</widget>
<widget class="QMenu" name="menuPaddingActions">
<property name="title">