mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-24 17:08:23 +08:00
Version 0.3.0
Refactor code to separate GUI from FFS ttraversal
This commit is contained in:
parent
1827c94977
commit
3ffbc01a3f
@ -2078,7 +2078,7 @@ void LzmaEnc_Finish(CLzmaEncHandle pp)
|
|||||||
if (p->mtMode)
|
if (p->mtMode)
|
||||||
MatchFinderMt_ReleaseStream(&p->matchFinderMt);
|
MatchFinderMt_ReleaseStream(&p->matchFinderMt);
|
||||||
#else
|
#else
|
||||||
//pp = pp;
|
pp = pp;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,12 @@ UINT8* calculateAddress16(UINT8* baseAddress, const UINT16 baseOrLimit)
|
|||||||
return baseAddress + baseOrLimit * 0x1000;
|
return baseAddress + baseOrLimit * 0x1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate offset of region using its base
|
||||||
|
UINT32 calculateRegionOffset(const UINT16 base)
|
||||||
|
{
|
||||||
|
return base * 0x1000;
|
||||||
|
}
|
||||||
|
|
||||||
//Calculate size of region using its base and limit
|
//Calculate size of region using its base and limit
|
||||||
UINT32 calculateRegionSize(const UINT16 base, const UINT16 limit)
|
UINT32 calculateRegionSize(const UINT16 base, const UINT16 limit)
|
||||||
{
|
{
|
||||||
|
@ -158,6 +158,9 @@ typedef struct {
|
|||||||
extern UINT8* calculateAddress8(UINT8* baseAddress, const UINT8 baseOrLimit);
|
extern UINT8* calculateAddress8(UINT8* baseAddress, const UINT8 baseOrLimit);
|
||||||
// 16 bit base or limit
|
// 16 bit base or limit
|
||||||
extern UINT8* calculateAddress16(UINT8* baseAddress, const UINT16 baseOrLimit);
|
extern UINT8* calculateAddress16(UINT8* baseAddress, const UINT16 baseOrLimit);
|
||||||
//Calculate size of region using its base and limit
|
|
||||||
|
// Calculate offset of region using its base
|
||||||
|
extern UINT32 calculateRegionOffset(const UINT16 base);
|
||||||
|
// Calculate size of region using its base and limit
|
||||||
extern UINT32 calculateRegionSize(const UINT16 base, const UINT16 limit);
|
extern UINT32 calculateRegionSize(const UINT16 base, const UINT16 limit);
|
||||||
#endif
|
#endif
|
1
ffs.cpp
1
ffs.cpp
@ -10,6 +10,7 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|||||||
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
#include "ffs.h"
|
#include "ffs.h"
|
||||||
|
|
||||||
const UINT8 ffsAlignmentTable[] =
|
const UINT8 ffsAlignmentTable[] =
|
||||||
|
1
ffs.h
1
ffs.h
@ -15,7 +15,6 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QObject>
|
|
||||||
#include "basetypes.h"
|
#include "basetypes.h"
|
||||||
|
|
||||||
// C++ functions
|
// C++ functions
|
||||||
|
1164
ffsengine.cpp
Normal file
1164
ffsengine.cpp
Normal file
File diff suppressed because it is too large
Load Diff
67
ffsengine.h
Normal file
67
ffsengine.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* ffsengine.h
|
||||||
|
|
||||||
|
Copyright (c) 2013, Nikolaj Schlej. All rights reserved.
|
||||||
|
This program and the accompanying materials
|
||||||
|
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
|
||||||
|
http://opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FFSENGINE_H__
|
||||||
|
#define __FFSENGINE_H__
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QModelIndex>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
#include "basetypes.h"
|
||||||
|
#include "treemodel.h"
|
||||||
|
|
||||||
|
class TreeModel;
|
||||||
|
|
||||||
|
class FfsEngine : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FfsEngine(QObject *parent = 0);
|
||||||
|
~FfsEngine(void);
|
||||||
|
|
||||||
|
TreeModel* model() const;
|
||||||
|
QString message() const;
|
||||||
|
|
||||||
|
UINT8 parseInputFile(const QByteArray & buffer);
|
||||||
|
UINT8* parseRegion(const QByteArray & flashImage, UINT8 regionSubtype, const UINT16 regionBase, const UINT16 regionLimit, QModelIndex & index);
|
||||||
|
UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex());
|
||||||
|
INT32 findNextVolume(const QByteArray & bios, INT32 volumeOffset = 0);
|
||||||
|
UINT32 getVolumeSize(const QByteArray & bios, INT32 volumeOffset);
|
||||||
|
UINT8 parseVolume(const QByteArray & volume, UINT32 volumeBase, UINT8 revision, bool erasePolarity, const QModelIndex & parent = QModelIndex());
|
||||||
|
UINT8 parseFile(const QByteArray & file, UINT8 revision, bool erasePolarity, const QModelIndex & parent = QModelIndex());
|
||||||
|
|
||||||
|
QModelIndex addTreeItem(const UINT8 type, const UINT8 subtype = 0, const UINT32 offset = 0,
|
||||||
|
const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(),
|
||||||
|
const QModelIndex & parent = QModelIndex());
|
||||||
|
bool removeItem(const QModelIndex &index);
|
||||||
|
|
||||||
|
QByteArray header(const QModelIndex& index) const;
|
||||||
|
bool hasEmptyHeader(const QModelIndex& index) const;
|
||||||
|
QByteArray body(const QModelIndex& index) const;
|
||||||
|
bool hasEmptyBody(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
bool isCompressedFile(const QModelIndex& index) const;
|
||||||
|
QByteArray uncompressFile(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString text;
|
||||||
|
TreeItem *rootItem;
|
||||||
|
TreeModel *treeModel;
|
||||||
|
void msg(const QString & message);
|
||||||
|
QModelIndex findParentOfType(UINT8 type, const QModelIndex& index) const;
|
||||||
|
bool setTreeItemName(const QString &data, const QModelIndex &index);
|
||||||
|
bool setTreeItemText(const QString &data, const QModelIndex &index);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
36
gbe.h
Normal file
36
gbe.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/* gbe.h
|
||||||
|
|
||||||
|
Copyright (c) 2013, Nikolaj Schlej. All rights reserved.
|
||||||
|
This program and the accompanying materials
|
||||||
|
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
|
||||||
|
http://opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GBE_H__
|
||||||
|
#define __GBE_H__
|
||||||
|
|
||||||
|
#include "basetypes.h"
|
||||||
|
|
||||||
|
// Make sure we use right packing rules
|
||||||
|
#pragma pack(push,1)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT8 vendor[3];
|
||||||
|
UINT8 device[3];
|
||||||
|
} GBE_MAC;
|
||||||
|
|
||||||
|
#define GBE_VERSION_OFFSET 10
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT8 id: 4;
|
||||||
|
UINT8 minor: 4;
|
||||||
|
UINT8 major;
|
||||||
|
} GBE_VERSION;
|
||||||
|
|
||||||
|
// Restore previous packing rules
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
34
me.h
Normal file
34
me.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* me.h
|
||||||
|
|
||||||
|
Copyright (c) 2013, Nikolaj Schlej. All rights reserved.
|
||||||
|
This program and the accompanying materials
|
||||||
|
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
|
||||||
|
http://opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ME_H__
|
||||||
|
#define __ME_H__
|
||||||
|
|
||||||
|
#include "basetypes.h"
|
||||||
|
|
||||||
|
// Make sure we use right packing rules
|
||||||
|
#pragma pack(push,1)
|
||||||
|
|
||||||
|
const QByteArray ME_VERSION_SIGNATURE("\x24\x4D\x4E\x32", 4);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT32 signature;
|
||||||
|
UINT32 reserved; // Unknown for me
|
||||||
|
UINT16 major;
|
||||||
|
UINT16 minor;
|
||||||
|
UINT16 bugfix;
|
||||||
|
UINT16 build;
|
||||||
|
} ME_VERSION;
|
||||||
|
|
||||||
|
// Restore previous packing rules
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
@ -12,14 +12,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "treeitem.h"
|
#include "treeitem.h"
|
||||||
#include "treeitemtypes.h"
|
|
||||||
|
|
||||||
TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const QString & name, const QString & typeName, const QString & subtypeName,
|
TreeItem::TreeItem(const UINT8 type, const UINT8 subtype, const UINT32 offset, const QString & name, const QString & typeName, const QString & subtypeName,
|
||||||
const QString & text, const QString & info, const QByteArray & header, const QByteArray & body, TreeItem *parent)
|
const QString & text, const QString & info, const QByteArray & header, const QByteArray & body, TreeItem *parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
itemType = type;
|
itemType = type;
|
||||||
itemSubtype = subtype;
|
itemSubtype = subtype;
|
||||||
|
itemOffset = offset;
|
||||||
itemName = name;
|
itemName = name;
|
||||||
itemTypeName = typeName;
|
itemTypeName = typeName;
|
||||||
itemSubtypeName = subtypeName;
|
itemSubtypeName = subtypeName;
|
||||||
@ -134,6 +134,11 @@ UINT8 TreeItem::subtype()
|
|||||||
return itemSubtype;
|
return itemSubtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT32 TreeItem::offset()
|
||||||
|
{
|
||||||
|
return itemOffset;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray TreeItem::header()
|
QByteArray TreeItem::header()
|
||||||
{
|
{
|
||||||
return itemHeader;
|
return itemHeader;
|
||||||
|
@ -23,7 +23,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
class TreeItem
|
class TreeItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TreeItem(const UINT8 type, const UINT8 subtype = 0, const QString & name = QString(), const QString & typeName = QString(), const QString & subtypeName = QString(),
|
TreeItem(const UINT8 type, const UINT8 subtype = 0, const UINT32 offset = 0, const QString & name = QString(), const QString & typeName = QString(), const QString & subtypeName = QString(),
|
||||||
const QString & text = QString(), const QString & info = QString(), const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), TreeItem *parent = 0);
|
const QString & text = QString(), const QString & info = QString(), const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), TreeItem *parent = 0);
|
||||||
~TreeItem();
|
~TreeItem();
|
||||||
|
|
||||||
@ -39,6 +39,7 @@ public:
|
|||||||
|
|
||||||
UINT8 type();
|
UINT8 type();
|
||||||
UINT8 subtype();
|
UINT8 subtype();
|
||||||
|
UINT32 offset();
|
||||||
QByteArray header();
|
QByteArray header();
|
||||||
QByteArray body();
|
QByteArray body();
|
||||||
QString info();
|
QString info();
|
||||||
@ -55,6 +56,7 @@ private:
|
|||||||
QList<TreeItem*> childItems;
|
QList<TreeItem*> childItems;
|
||||||
UINT8 itemType;
|
UINT8 itemType;
|
||||||
UINT8 itemSubtype;
|
UINT8 itemSubtype;
|
||||||
|
UINT32 itemOffset;
|
||||||
QByteArray itemHeader;
|
QByteArray itemHeader;
|
||||||
QByteArray itemBody;
|
QByteArray itemBody;
|
||||||
QString itemName;
|
QString itemName;
|
||||||
|
235
treemodel.cpp
235
treemodel.cpp
@ -13,41 +13,17 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
|
|
||||||
#include "treeitem.h"
|
#include "treeitem.h"
|
||||||
#include "treemodel.h"
|
#include "treemodel.h"
|
||||||
#include "ffs.h"
|
|
||||||
#include "descriptor.h"
|
|
||||||
|
|
||||||
TreeModel::TreeModel(QObject *parent)
|
TreeModel::TreeModel(TreeItem *root, QObject *parent)
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
{
|
{
|
||||||
rootItem = new TreeItem(RootItem, 0, tr("Object"), tr("Type"), tr("Subtype"), tr("Text"));
|
rootItem = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeModel::~TreeModel()
|
TreeModel::~TreeModel()
|
||||||
{
|
{
|
||||||
delete rootItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TreeModel::hasEmptyHeader(const QModelIndex& index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
|
|
||||||
|
|
||||||
return item->hasEmptyHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TreeModel::hasEmptyBody(const QModelIndex& index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
|
|
||||||
|
|
||||||
return item->hasEmptyBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int TreeModel::columnCount(const QModelIndex &parent) const
|
int TreeModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (parent.isValid())
|
if (parent.isValid())
|
||||||
@ -140,153 +116,6 @@ int TreeModel::rowCount(const QModelIndex &parent) const
|
|||||||
return parentItem->childCount();
|
return parentItem->childCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex TreeModel::addItem(UINT8 type, UINT8 subtype, const QByteArray &header, const QByteArray &body, const QModelIndex &parent)
|
|
||||||
{
|
|
||||||
TreeItem *parentItem;
|
|
||||||
int parentColumn = 0;
|
|
||||||
|
|
||||||
if (!parent.isValid())
|
|
||||||
parentItem = rootItem;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
|
||||||
parentColumn = parent.column();
|
|
||||||
}
|
|
||||||
|
|
||||||
// All information extraction must be here
|
|
||||||
QString name, typeName, subtypeName, info;
|
|
||||||
EFI_CAPSULE_HEADER* capsuleHeader;
|
|
||||||
APTIO_CAPSULE_HEADER* aptioCapsuleHeader;
|
|
||||||
FLASH_DESCRIPTOR_MAP* descriptorMap;
|
|
||||||
//FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection;
|
|
||||||
//FLASH_DESCRIPTOR_REGION_SECTION* regionSection;
|
|
||||||
//FLASH_DESCRIPTOR_MASTER_SECTION* masterSection;
|
|
||||||
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader;
|
|
||||||
EFI_FFS_FILE_HEADER* fileHeader;
|
|
||||||
//EFI_COMMON_SECTION_HEADER* sectionHeader;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case RootItem:
|
|
||||||
// Do not allow to add another root item
|
|
||||||
return QModelIndex();
|
|
||||||
break;
|
|
||||||
case CapsuleItem:
|
|
||||||
//typeName = tr("Capsule");
|
|
||||||
switch (subtype)
|
|
||||||
{
|
|
||||||
case AptioCapsule:
|
|
||||||
name = tr("AMI Aptio capsule");
|
|
||||||
aptioCapsuleHeader = (APTIO_CAPSULE_HEADER*) header.constData();
|
|
||||||
info = tr("GUID: %1\nHeader size: %2\nFlags: %3\nImage size: %4")
|
|
||||||
.arg(guidToQString(aptioCapsuleHeader->CapsuleHeader.CapsuleGuid))
|
|
||||||
.arg(aptioCapsuleHeader->CapsuleHeader.Flags, 8, 16, QChar('0'))
|
|
||||||
.arg(aptioCapsuleHeader->RomImageOffset, 4, 16, QChar('0'))
|
|
||||||
.arg(aptioCapsuleHeader->CapsuleHeader.CapsuleImageSize - aptioCapsuleHeader->RomImageOffset, 8, 16, QChar('0'));
|
|
||||||
//!TODO: more info about Aptio capsule
|
|
||||||
break;
|
|
||||||
case UefiCapsule:
|
|
||||||
name = tr("UEFI capsule");
|
|
||||||
capsuleHeader = (EFI_CAPSULE_HEADER*) header.constData();
|
|
||||||
info = tr("GUID: %1\nHeader size: %2\nFlags: %3\nImage size: %4")
|
|
||||||
.arg(guidToQString(capsuleHeader->CapsuleGuid))
|
|
||||||
.arg(capsuleHeader->Flags, 8, 16, QChar('0'))
|
|
||||||
.arg(capsuleHeader->HeaderSize, 8, 16, QChar('0'))
|
|
||||||
.arg(capsuleHeader->CapsuleImageSize, 8, 16, QChar('0'));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = tr("Unknown capsule");
|
|
||||||
info = tr("GUID: %1\n").arg(guidToQString(*(EFI_GUID*)header.constData()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DescriptorItem:
|
|
||||||
name = tr("Descriptor");
|
|
||||||
descriptorMap = (FLASH_DESCRIPTOR_MAP*) body.constData();
|
|
||||||
info = tr("Flash chips: %1\nRegions: %2\nMasters: %3\nPCH straps:%4\nPROC straps: %5\nICC table entries: %6")
|
|
||||||
.arg(descriptorMap->NumberOfFlashChips + 1) //
|
|
||||||
.arg(descriptorMap->NumberOfRegions + 1) // Zero-based numbers in storage
|
|
||||||
.arg(descriptorMap->NumberOfMasters + 1) //
|
|
||||||
.arg(descriptorMap->NumberOfPchStraps)
|
|
||||||
.arg(descriptorMap->NumberOfProcStraps)
|
|
||||||
.arg(descriptorMap->NumberOfIccTableEntries);
|
|
||||||
//!TODO: more info about descriptor
|
|
||||||
break;
|
|
||||||
case RegionItem:
|
|
||||||
typeName = tr("Region");
|
|
||||||
info = tr("Size: %1").arg(body.size(), 8, 16, QChar('0'));
|
|
||||||
//!TODO: more info about GbE and ME regions
|
|
||||||
switch (subtype)
|
|
||||||
{
|
|
||||||
case GbeRegion:
|
|
||||||
name = tr("GbE region");
|
|
||||||
break;
|
|
||||||
case MeRegion:
|
|
||||||
name = tr("ME region");
|
|
||||||
break;
|
|
||||||
case BiosRegion:
|
|
||||||
name = tr("BIOS region");
|
|
||||||
break;
|
|
||||||
case PdrRegion:
|
|
||||||
name = tr("PDR region");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = tr("Unknown region");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PaddingItem:
|
|
||||||
name = tr("Padding");
|
|
||||||
info = tr("Size: %1").arg(body.size(), 8, 16, QChar('0'));
|
|
||||||
break;
|
|
||||||
case VolumeItem:
|
|
||||||
typeName = tr("Volume");
|
|
||||||
// Parse volume header to determine its revision and file system
|
|
||||||
volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) header.constData();
|
|
||||||
name = guidToQString(volumeHeader->FileSystemGuid);
|
|
||||||
subtypeName = tr("Revision %1").arg(volumeHeader->Revision);
|
|
||||||
info = tr("Size: %1\nSignature: %2\nAttributes: %3\nHeader size: %4")
|
|
||||||
.arg(volumeHeader->FvLength, 8, 16, QChar('0'))
|
|
||||||
.arg(volumeHeader->Signature, 8, 16, QChar('0'))
|
|
||||||
.arg(volumeHeader->Attributes, 8, 16, QChar('0'))
|
|
||||||
.arg(volumeHeader->HeaderLength, 4, 16, QChar('0'));
|
|
||||||
break;
|
|
||||||
case FileItem:
|
|
||||||
typeName = tr("File");
|
|
||||||
// Parse file header to determine its GUID and type
|
|
||||||
fileHeader = (EFI_FFS_FILE_HEADER*) header.constData();
|
|
||||||
name = guidToQString(fileHeader->Name);
|
|
||||||
subtypeName = fileTypeToQString(subtype);
|
|
||||||
info = tr("Type: %1\nAttributes: %2\nSize: %3\nState: %4")
|
|
||||||
.arg(fileHeader->Type, 2, 16, QChar('0'))
|
|
||||||
.arg(fileHeader->Attributes, 2, 16, QChar('0'))
|
|
||||||
.arg(uint24ToUint32(fileHeader->Size), 6, 16, QChar('0'))
|
|
||||||
.arg(fileHeader->State, 2, 16, QChar('0'));
|
|
||||||
break;
|
|
||||||
case SectionItem:
|
|
||||||
typeName = tr("Section");
|
|
||||||
name = sectionTypeToQString(subtype) + tr(" section");
|
|
||||||
info = tr("Size: %1").arg(body.size(), 8, 16, QChar('0'));
|
|
||||||
//!TODO: add more specific info for all section types with uncommon headers
|
|
||||||
// Set name of file
|
|
||||||
if (subtype == UserInterfaceSection)
|
|
||||||
{
|
|
||||||
QString text = QString::fromUtf16((const ushort*)body.constData());
|
|
||||||
setItemText(text, findParentOfType(FileItem, parent));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = tr("Unknown");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit layoutAboutToBeChanged();
|
|
||||||
TreeItem *item = new TreeItem(type, subtype, name, typeName, subtypeName, "", info, header, body, parentItem);
|
|
||||||
parentItem->appendChild(item);
|
|
||||||
emit layoutChanged();
|
|
||||||
return createIndex(parentItem->childCount() - 1, parentColumn, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TreeModel::setItemName(const QString &data, const QModelIndex &index)
|
bool TreeModel::setItemName(const QString &data, const QModelIndex &index)
|
||||||
{
|
{
|
||||||
if(!index.isValid())
|
if(!index.isValid())
|
||||||
@ -309,46 +138,24 @@ bool TreeModel::setItemText(const QString &data, const QModelIndex &index)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TreeModel::removeItem(const QModelIndex &index)
|
QModelIndex TreeModel::addItem(const UINT8 type, const UINT8 subtype, const UINT32 offset, const QString & name, const QString & typeName,
|
||||||
|
const QString & subtypeName, const QString & text, const QString & info,
|
||||||
|
const QByteArray & header, const QByteArray & body, const QModelIndex & parent)
|
||||||
{
|
{
|
||||||
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
|
TreeItem *parentItem;
|
||||||
item->parent()->removeChild(item);
|
int parentColumn = 0;
|
||||||
delete item;
|
|
||||||
return true;
|
if (!parent.isValid())
|
||||||
}
|
parentItem = rootItem;
|
||||||
|
else
|
||||||
QModelIndex TreeModel::findParentOfType(UINT8 type, const QModelIndex& index)
|
{
|
||||||
{
|
parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
||||||
if(!index.isValid())
|
parentColumn = parent.column();
|
||||||
return QModelIndex();
|
}
|
||||||
|
|
||||||
TreeItem *item;
|
emit layoutAboutToBeChanged();
|
||||||
QModelIndex parent = index;
|
TreeItem *item = new TreeItem(type, subtype, offset, name, typeName, subtypeName, text, info, header, body, parentItem);
|
||||||
|
parentItem->appendChild(item);
|
||||||
for(item = static_cast<TreeItem*>(parent.internalPointer());
|
emit layoutChanged();
|
||||||
item != NULL && item != rootItem && item->type() != type;
|
return createIndex(parentItem->childCount() - 1, parentColumn, item);
|
||||||
item = static_cast<TreeItem*>(parent.internalPointer()))
|
|
||||||
parent = parent.parent();
|
|
||||||
if (item != NULL && item != rootItem)
|
|
||||||
return parent;
|
|
||||||
|
|
||||||
return QModelIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray TreeModel::header(const QModelIndex& index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return QByteArray();
|
|
||||||
|
|
||||||
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
|
|
||||||
return item->header();
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray TreeModel::body(const QModelIndex& index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return QByteArray();
|
|
||||||
|
|
||||||
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
|
|
||||||
return item->body();
|
|
||||||
}
|
}
|
19
treemodel.h
19
treemodel.h
@ -20,7 +20,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
#include "basetypes.h"
|
#include "basetypes.h"
|
||||||
#include "treeitemtypes.h"
|
|
||||||
|
|
||||||
class TreeItem;
|
class TreeItem;
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ class TreeModel : public QAbstractItemModel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TreeModel(QObject *parent = 0);
|
TreeModel(TreeItem *root, QObject *parent = 0);
|
||||||
~TreeModel();
|
~TreeModel();
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
@ -42,18 +41,14 @@ public:
|
|||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
|
||||||
QModelIndex addItem(UINT8 type, UINT8 subtype = 0, const QByteArray &header = QByteArray(), const QByteArray &body = QByteArray(), const QModelIndex &parent = QModelIndex());
|
|
||||||
bool removeItem(const QModelIndex &index);
|
|
||||||
|
|
||||||
QByteArray header(const QModelIndex& index);
|
|
||||||
bool hasEmptyHeader(const QModelIndex& index);
|
|
||||||
QByteArray body(const QModelIndex& index);
|
|
||||||
bool hasEmptyBody(const QModelIndex& index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QModelIndex findParentOfType(UINT8 type, const QModelIndex& index);
|
|
||||||
bool setItemName(const QString &data, const QModelIndex &index);
|
bool setItemName(const QString &data, const QModelIndex &index);
|
||||||
bool setItemText(const QString &data, const QModelIndex &index);
|
bool setItemText(const QString &data, const QModelIndex &index);
|
||||||
|
|
||||||
|
QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT32 offset = 0, const QString & name = QString(),
|
||||||
|
const QString & typeName = QString(), const QString & subtypeName = QString(), const QString & text = QString(),
|
||||||
|
const QString & info = QString(), const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QModelIndex & parent = QModelIndex());
|
||||||
|
|
||||||
|
private:
|
||||||
TreeItem *rootItem;
|
TreeItem *rootItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
847
uefitool.cpp
847
uefitool.cpp
@ -12,7 +12,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "uefitool.h"
|
#include "uefitool.h"
|
||||||
#include "treeitemtypes.h"
|
|
||||||
#include "ui_uefitool.h"
|
#include "ui_uefitool.h"
|
||||||
|
|
||||||
UEFITool::UEFITool(QWidget *parent) :
|
UEFITool::UEFITool(QWidget *parent) :
|
||||||
@ -20,13 +19,13 @@ UEFITool::UEFITool(QWidget *parent) :
|
|||||||
ui(new Ui::UEFITool)
|
ui(new Ui::UEFITool)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
treeModel = NULL;
|
ffsEngine = NULL;
|
||||||
|
|
||||||
// Signal-slot connections
|
|
||||||
connect(ui->fromFileButton, SIGNAL(clicked()), this, SLOT(openImageFile()));
|
|
||||||
connect(ui->exportAllButton, SIGNAL(clicked()), this, SLOT(saveAll()));
|
|
||||||
connect(ui->exportBodyButton, SIGNAL(clicked()), this, SLOT(saveBody()));
|
|
||||||
|
|
||||||
|
//Connect
|
||||||
|
connect(ui->actionOpenImageFile, SIGNAL(triggered()), this, SLOT(openImageFile()));
|
||||||
|
connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(saveAll()));
|
||||||
|
connect(ui->actionExtractBody, SIGNAL(triggered()), this, SLOT(saveBody()));
|
||||||
|
connect(ui->actionExtractUncompressed, SIGNAL(triggered()), this, SLOT(saveUncompressedFile()));
|
||||||
// Enable Drag-and-Drop actions
|
// Enable Drag-and-Drop actions
|
||||||
this->setAcceptDrops(true);
|
this->setAcceptDrops(true);
|
||||||
|
|
||||||
@ -37,7 +36,7 @@ UEFITool::UEFITool(QWidget *parent) :
|
|||||||
UEFITool::~UEFITool()
|
UEFITool::~UEFITool()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
delete treeModel;
|
delete ffsEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UEFITool::init()
|
void UEFITool::init()
|
||||||
@ -45,19 +44,26 @@ void UEFITool::init()
|
|||||||
// Clear UI components
|
// Clear UI components
|
||||||
ui->debugEdit->clear();
|
ui->debugEdit->clear();
|
||||||
ui->infoEdit->clear();
|
ui->infoEdit->clear();
|
||||||
ui->exportAllButton->setDisabled(true);
|
|
||||||
ui->exportBodyButton->setDisabled(true);
|
// Disable all actions except openImageFile
|
||||||
// Make new tree model
|
ui->actionExtract->setDisabled(true);
|
||||||
TreeModel * newModel = new TreeModel(this);
|
ui->actionExtractBody->setDisabled(true);
|
||||||
ui->structureTreeView->setModel(newModel);
|
ui->actionExtractUncompressed->setDisabled(true);
|
||||||
if (treeModel)
|
ui->actionReplace->setDisabled(true);
|
||||||
delete treeModel;
|
ui->actionDelete->setDisabled(true);
|
||||||
treeModel = newModel;
|
ui->actionReplaceWithPadding->setDisabled(true);
|
||||||
// Show info after selection the item in tree view
|
ui->actionInsertBefore->setDisabled(true);
|
||||||
|
ui->actionInsertAfter->setDisabled(true);
|
||||||
|
|
||||||
|
// Make new ffsEngine
|
||||||
|
ffsEngine = new FfsEngine(this);
|
||||||
|
ui->structureTreeView->setModel(ffsEngine->model());
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
connect(ui->structureTreeView, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
||||||
|
connect(ui->structureTreeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
||||||
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||||
this, SLOT(populateUi(const QModelIndex &)));
|
this, SLOT(populateUi(const QModelIndex &)));
|
||||||
//connect(ui->structureTreeView, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
|
||||||
connect(ui->structureTreeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
|
||||||
resizeTreeViewColums();
|
resizeTreeViewColums();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,13 +72,14 @@ void UEFITool::populateUi(const QModelIndex ¤t/*, const QModelIndex &previ
|
|||||||
//!TODO: make widget
|
//!TODO: make widget
|
||||||
currentIndex = current;
|
currentIndex = current;
|
||||||
ui->infoEdit->setPlainText(current.data(Qt::UserRole).toString());
|
ui->infoEdit->setPlainText(current.data(Qt::UserRole).toString());
|
||||||
ui->exportAllButton->setDisabled(treeModel->hasEmptyBody(current) && treeModel->hasEmptyHeader(current));
|
ui->actionExtract->setDisabled(ffsEngine->hasEmptyBody(current) && ffsEngine->hasEmptyHeader(current));
|
||||||
ui->exportBodyButton->setDisabled(treeModel->hasEmptyHeader(current));
|
ui->actionExtractBody->setDisabled(ffsEngine->hasEmptyHeader(current));
|
||||||
|
ui->actionExtractUncompressed->setEnabled(ffsEngine->isCompressedFile(current));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UEFITool::resizeTreeViewColums(/*const QModelIndex &index*/)
|
void UEFITool::resizeTreeViewColums(/*const QModelIndex &index*/)
|
||||||
{
|
{
|
||||||
int count = treeModel->columnCount();
|
int count = ffsEngine->model()->columnCount();
|
||||||
for(int i = 0; i < count; i++)
|
for(int i = 0; i < count; i++)
|
||||||
ui->structureTreeView->resizeColumnToContents(i);
|
ui->structureTreeView->resizeColumnToContents(i);
|
||||||
}
|
}
|
||||||
@ -105,17 +112,19 @@ void UEFITool::openImageFile(QString path)
|
|||||||
inputFile.close();
|
inputFile.close();
|
||||||
|
|
||||||
init();
|
init();
|
||||||
UINT8 result = parseInputFile(buffer);
|
UINT8 result = ffsEngine->parseInputFile(buffer);
|
||||||
if (result)
|
if (result)
|
||||||
debug(tr("Opened file can't be parsed as UEFI image (%1)").arg(result));
|
ui->statusBar->showMessage(tr("Opened file can't be parsed as UEFI image (%1)").arg(result));
|
||||||
else
|
else
|
||||||
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
|
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
|
||||||
|
|
||||||
|
ui->debugEdit->appendPlainText(ffsEngine->message());
|
||||||
resizeTreeViewColums();
|
resizeTreeViewColums();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UEFITool::saveAll()
|
void UEFITool::saveAll()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getSaveFileName(this, tr("Save header to binary file"),".","Binary files (*.bin);;All files (*.*)");
|
QString path = QFileDialog::getSaveFileName(this, tr("Save selected item to binary file"),".","Binary files (*.bin);;All files (*.*)");
|
||||||
|
|
||||||
QFile outputFile;
|
QFile outputFile;
|
||||||
outputFile.setFileName(path);
|
outputFile.setFileName(path);
|
||||||
@ -125,13 +134,13 @@ void UEFITool::saveAll()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
outputFile.write(treeModel->header(currentIndex) + treeModel->body(currentIndex));
|
outputFile.write(ffsEngine->header(currentIndex) + ffsEngine->body(currentIndex));
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UEFITool::saveBody()
|
void UEFITool::saveBody()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getSaveFileName(this, tr("Save body to binary file"),".","Binary files (*.bin);;All files (*.*)");
|
QString path = QFileDialog::getSaveFileName(this, tr("Save selected item without header to binary file"),".","Binary files (*.bin);;All files (*.*)");
|
||||||
|
|
||||||
QFile outputFile;
|
QFile outputFile;
|
||||||
outputFile.setFileName(path);
|
outputFile.setFileName(path);
|
||||||
@ -141,7 +150,23 @@ void UEFITool::saveBody()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
outputFile.write(treeModel->body(currentIndex));
|
outputFile.write(ffsEngine->body(currentIndex));
|
||||||
|
outputFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEFITool::saveUncompressedFile()
|
||||||
|
{
|
||||||
|
QString path = QFileDialog::getSaveFileName(this, tr("Save selected FFS file as uncompressed to binary file"),".","FFS files (*.ffs);;All files (*.*)");
|
||||||
|
|
||||||
|
QFile outputFile;
|
||||||
|
outputFile.setFileName(path);
|
||||||
|
if (!outputFile.open(QFile::WriteOnly))
|
||||||
|
{
|
||||||
|
ui->statusBar->showMessage(tr("Can't open file for writing. Check file permissions."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFile.write(ffsEngine->uncompressFile(currentIndex));
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,769 +202,3 @@ void UEFITool::dropEvent(QDropEvent* event)
|
|||||||
openImageFile(path);
|
openImageFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UEFITool::debug(const QString & text)
|
|
||||||
{
|
|
||||||
//!TODO: log to separate debug window
|
|
||||||
ui->debugEdit->appendPlainText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex UEFITool::addTreeItem(UINT8 type, UINT8 subtype,
|
|
||||||
const QByteArray & header, const QByteArray & body, const QModelIndex & parent)
|
|
||||||
{
|
|
||||||
return treeModel->addItem(type, subtype, header, body, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8 UEFITool::parseInputFile(const QByteArray & buffer)
|
|
||||||
{
|
|
||||||
UINT32 capsuleHeaderSize = 0;
|
|
||||||
FLASH_DESCRIPTOR_HEADER* descriptorHeader = NULL;
|
|
||||||
QByteArray flashImage;
|
|
||||||
QByteArray bios;
|
|
||||||
QModelIndex index;
|
|
||||||
|
|
||||||
// Check buffer for being normal EFI capsule header
|
|
||||||
if (buffer.startsWith(EFI_CAPSULE_GUID)) {
|
|
||||||
EFI_CAPSULE_HEADER* capsuleHeader = (EFI_CAPSULE_HEADER*) buffer.constData();
|
|
||||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
|
||||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
|
||||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
|
||||||
index = addTreeItem(CapsuleItem, UefiCapsule, header, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check buffer for being extended Aptio capsule header
|
|
||||||
else if (buffer.startsWith(APTIO_CAPSULE_GUID)) {
|
|
||||||
APTIO_CAPSULE_HEADER* aptioCapsuleHeader = (APTIO_CAPSULE_HEADER*) buffer.constData();
|
|
||||||
capsuleHeaderSize = aptioCapsuleHeader->RomImageOffset;
|
|
||||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
|
||||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
|
||||||
index = addTreeItem(CapsuleItem, AptioCapsule, header, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip capsule header to have flash chip image
|
|
||||||
flashImage = buffer.right(buffer.size() - capsuleHeaderSize);
|
|
||||||
|
|
||||||
// Check buffer for being Intel flash descriptor
|
|
||||||
descriptorHeader = (FLASH_DESCRIPTOR_HEADER*) flashImage.constData();
|
|
||||||
// Check descriptor signature
|
|
||||||
if (descriptorHeader->Signature == FLASH_DESCRIPTOR_SIGNATURE) {
|
|
||||||
FLASH_DESCRIPTOR_MAP* descriptorMap;
|
|
||||||
FLASH_DESCRIPTOR_REGION_SECTION* regionSection;
|
|
||||||
|
|
||||||
// Store the beginning of descriptor as descriptor base address
|
|
||||||
UINT8* descriptor = (UINT8*) flashImage.constData();
|
|
||||||
UINT8* gbeRegion = NULL;
|
|
||||||
UINT8* meRegion = NULL;
|
|
||||||
UINT8* biosRegion = NULL;
|
|
||||||
UINT8* pdrRegion = NULL;
|
|
||||||
|
|
||||||
// Check for buffer size to be greater or equal to descriptor region size
|
|
||||||
if (flashImage.size() < FLASH_DESCRIPTOR_SIZE) {
|
|
||||||
debug(tr("Input file is smaller then mininum descriptor size of 4KB"));
|
|
||||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse descriptor map
|
|
||||||
descriptorMap = (FLASH_DESCRIPTOR_MAP*) (flashImage.constData() + sizeof(FLASH_DESCRIPTOR_HEADER));
|
|
||||||
regionSection = (FLASH_DESCRIPTOR_REGION_SECTION*) calculateAddress8(descriptor, descriptorMap->RegionBase);
|
|
||||||
|
|
||||||
// Add tree item
|
|
||||||
QByteArray header = flashImage.left(sizeof(FLASH_DESCRIPTOR_HEADER));
|
|
||||||
QByteArray body = flashImage.mid(sizeof(FLASH_DESCRIPTOR_HEADER), FLASH_DESCRIPTOR_SIZE - sizeof(FLASH_DESCRIPTOR_HEADER));
|
|
||||||
index = addTreeItem(DescriptorItem, 0, header, body, index);
|
|
||||||
|
|
||||||
// Parse region section
|
|
||||||
QModelIndex gbeIndex(index);
|
|
||||||
QModelIndex meIndex(index);
|
|
||||||
QModelIndex biosIndex(index);
|
|
||||||
QModelIndex pdrIndex(index);
|
|
||||||
gbeRegion = parseRegion(flashImage, GbeRegion, regionSection->GbeBase, regionSection->GbeLimit, gbeIndex);
|
|
||||||
meRegion = parseRegion(flashImage, MeRegion, regionSection->MeBase, regionSection->MeLimit, meIndex);
|
|
||||||
biosRegion = parseRegion(flashImage, BiosRegion, regionSection->BiosBase, regionSection->BiosLimit, biosIndex);
|
|
||||||
pdrRegion = parseRegion(flashImage, PdrRegion, regionSection->PdrBase, regionSection->PdrLimit, pdrIndex);
|
|
||||||
|
|
||||||
// Parse complete
|
|
||||||
//!TODO: show some info about GbE, ME and PDR regions if found
|
|
||||||
|
|
||||||
// Exit if no bios region found
|
|
||||||
if (!biosRegion) {
|
|
||||||
debug(tr("BIOS region not found"));
|
|
||||||
return ERR_BIOS_REGION_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = biosIndex;
|
|
||||||
bios = QByteArray::fromRawData((const char*) biosRegion, calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bios = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are in the beginning of BIOS space, where firmware volumes are
|
|
||||||
// Parse BIOS space
|
|
||||||
|
|
||||||
return parseBios(bios, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8* UEFITool::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype, const UINT16 regionBase, const UINT16 regionLimit, QModelIndex & index)
|
|
||||||
{
|
|
||||||
// Check for empty region
|
|
||||||
if (!regionLimit)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Calculate region size
|
|
||||||
UINT32 regionSize = calculateRegionSize(regionBase, regionLimit);
|
|
||||||
|
|
||||||
// Populate descriptor map
|
|
||||||
FLASH_DESCRIPTOR_MAP* descriptor_map = (FLASH_DESCRIPTOR_MAP*) (flashImage.constData() + sizeof(FLASH_DESCRIPTOR_HEADER));
|
|
||||||
|
|
||||||
// Determine presence of 2 flash chips
|
|
||||||
bool twoChips = descriptor_map->NumberOfFlashChips;
|
|
||||||
|
|
||||||
// construct region name
|
|
||||||
//!TODO: make this to regionTypeToQString(const UINT8 type) in descriptor.cpp
|
|
||||||
QString regionName;
|
|
||||||
switch (regionSubtype)
|
|
||||||
{
|
|
||||||
case GbeRegion:
|
|
||||||
regionName = "GbE";
|
|
||||||
break;
|
|
||||||
case MeRegion:
|
|
||||||
regionName = "ME";
|
|
||||||
break;
|
|
||||||
case BiosRegion:
|
|
||||||
regionName = "Bios";
|
|
||||||
break;
|
|
||||||
case PdrRegion:
|
|
||||||
regionName = "PDR";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
regionName = "Unknown";
|
|
||||||
debug(tr("Unknown region type"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check region base to be in buffer
|
|
||||||
if (regionBase * 0x1000 >= flashImage.size())
|
|
||||||
{
|
|
||||||
debug(tr("%1 region stored in descriptor not found").arg(regionName));
|
|
||||||
if (twoChips)
|
|
||||||
debug(tr("Two flash chips installed, so it could be in another flash chip\n"
|
|
||||||
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName));
|
|
||||||
else
|
|
||||||
debug(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
|
|
||||||
debug(tr("Absence of %1 region assumed").arg(regionName));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check region to be fully present in buffer
|
|
||||||
else if (regionBase * 0x1000 + regionSize > flashImage.size())
|
|
||||||
{
|
|
||||||
debug(tr("%s region stored in descriptor overlaps the end of opened file").arg(regionName));
|
|
||||||
if (twoChips)
|
|
||||||
debug(tr("Two flash chips installed, so it could be in another flash chip\n"
|
|
||||||
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName));
|
|
||||||
else
|
|
||||||
debug(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
|
|
||||||
debug(tr("Absence of %1 region assumed\n").arg(regionName));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate region address
|
|
||||||
UINT8* region = calculateAddress16((UINT8*) flashImage.constData(), regionBase);
|
|
||||||
|
|
||||||
// Add tree item
|
|
||||||
QByteArray body = flashImage.mid(regionBase * 0x1000, regionSize);
|
|
||||||
index = addTreeItem(RegionItem, regionSubtype, QByteArray(), body, index);
|
|
||||||
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8 UEFITool::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
|
||||||
{
|
|
||||||
// Search for first volume
|
|
||||||
INT32 prevVolumeIndex = getNextVolumeIndex(bios);
|
|
||||||
|
|
||||||
// No volumes found
|
|
||||||
if (prevVolumeIndex < 0) {
|
|
||||||
return ERR_VOLUMES_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First volume is not at the beginning of bios space
|
|
||||||
if (prevVolumeIndex > 0) {
|
|
||||||
QByteArray padding = bios.left(prevVolumeIndex);
|
|
||||||
addTreeItem(PaddingItem, 0, QByteArray(), padding, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for and parse all volumes
|
|
||||||
INT32 volumeIndex;
|
|
||||||
UINT32 prevVolumeSize;
|
|
||||||
for (volumeIndex = prevVolumeIndex, prevVolumeSize = 0;
|
|
||||||
volumeIndex >= 0;
|
|
||||||
prevVolumeIndex = volumeIndex, prevVolumeSize = getVolumeSize(bios, volumeIndex), volumeIndex = getNextVolumeIndex(bios, volumeIndex + prevVolumeSize))
|
|
||||||
{
|
|
||||||
// Padding between volumes
|
|
||||||
if (volumeIndex > prevVolumeIndex + prevVolumeSize) {
|
|
||||||
UINT32 size = volumeIndex - prevVolumeIndex - prevVolumeSize;
|
|
||||||
QByteArray padding = bios.mid(prevVolumeIndex + prevVolumeSize, size);
|
|
||||||
addTreeItem(PaddingItem, 0, QByteArray(), padding, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate volume header
|
|
||||||
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) (bios.constData() + volumeIndex);
|
|
||||||
|
|
||||||
//Check that volume is fully present in input
|
|
||||||
if (volumeIndex + volumeHeader->FvLength > bios.size()) {
|
|
||||||
debug(tr("Volume overlaps the end of input buffer"));
|
|
||||||
return ERR_INVALID_VOLUME;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check volume revision and alignment
|
|
||||||
UINT32 alignment;
|
|
||||||
if (volumeHeader->Revision == 1) {
|
|
||||||
// Aquire alignment bits
|
|
||||||
bool alignmentCap = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_CAP;
|
|
||||||
bool alignment2 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_2;
|
|
||||||
bool alignment4 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_4;
|
|
||||||
bool alignment8 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_8;
|
|
||||||
bool alignment16 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_16;
|
|
||||||
bool alignment32 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_32;
|
|
||||||
bool alignment64 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_64;
|
|
||||||
bool alignment128 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_128;
|
|
||||||
bool alignment256 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_256;
|
|
||||||
bool alignment512 = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_512;
|
|
||||||
bool alignment1k = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_1K;
|
|
||||||
bool alignment2k = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_2K;
|
|
||||||
bool alignment4k = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_4K;
|
|
||||||
bool alignment8k = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_8K;
|
|
||||||
bool alignment16k = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_16K;
|
|
||||||
bool alignment32k = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_32K;
|
|
||||||
bool alignment64k = volumeHeader->Attributes & EFI_FVB_ALIGNMENT_64K;
|
|
||||||
|
|
||||||
// Check alignment setup
|
|
||||||
if (!alignmentCap &&
|
|
||||||
( alignment2 || alignment4 || alignment8 || alignment16
|
|
||||||
|| alignment32 || alignment64 || alignment128 || alignment256
|
|
||||||
|| alignment512 || alignment1k || alignment2k || alignment4k
|
|
||||||
|| alignment8k || alignment16k || alignment32k || alignment64k))
|
|
||||||
debug("Incompatible revision 1 volume alignment setup");
|
|
||||||
|
|
||||||
// Assume that smaller alignment value consumes greater
|
|
||||||
alignment = 0x01;
|
|
||||||
if (alignment2)
|
|
||||||
alignment = 0x02;
|
|
||||||
else if (alignment4)
|
|
||||||
alignment = 0x04;
|
|
||||||
else if (alignment8)
|
|
||||||
alignment = 0x08;
|
|
||||||
else if (alignment16)
|
|
||||||
alignment = 0x10;
|
|
||||||
else if (alignment32)
|
|
||||||
alignment = 0x20;
|
|
||||||
else if (alignment64)
|
|
||||||
alignment = 0x40;
|
|
||||||
else if (alignment128)
|
|
||||||
alignment = 0x80;
|
|
||||||
else if (alignment256)
|
|
||||||
alignment = 0x100;
|
|
||||||
else if (alignment512)
|
|
||||||
alignment = 0x200;
|
|
||||||
else if (alignment1k)
|
|
||||||
alignment = 0x400;
|
|
||||||
else if (alignment2k)
|
|
||||||
alignment = 0x800;
|
|
||||||
else if (alignment4k)
|
|
||||||
alignment = 0x1000;
|
|
||||||
else if (alignment8k)
|
|
||||||
alignment = 0x2000;
|
|
||||||
else if (alignment16k)
|
|
||||||
alignment = 0x4000;
|
|
||||||
else if (alignment32k)
|
|
||||||
alignment = 0x8000;
|
|
||||||
else if (alignment64k)
|
|
||||||
alignment = 0x10000;
|
|
||||||
|
|
||||||
// Check alignment
|
|
||||||
if (volumeIndex % alignment) {
|
|
||||||
debug(tr("Unaligned revision 1 volume"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (volumeHeader->Revision == 2) {
|
|
||||||
// Aquire alignment
|
|
||||||
alignment = pow(2, (volumeHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
|
|
||||||
|
|
||||||
// Check alignment
|
|
||||||
if (volumeIndex % alignment) {
|
|
||||||
debug(tr("Unaligned revision 2 volume"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
debug(tr("Unknown volume revision (%1)").arg(volumeHeader->Revision));
|
|
||||||
|
|
||||||
// Check filesystem GUID to be known
|
|
||||||
// Do not parse volume with unknown FFS, because parsing will fail
|
|
||||||
bool parseCurrentVolume = true;
|
|
||||||
// FFS GUID v1
|
|
||||||
if (QByteArray((const char*) &volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_FILE_SYSTEM_GUID) {
|
|
||||||
// Code can be added here
|
|
||||||
}
|
|
||||||
// FFS GUID v2
|
|
||||||
else if (QByteArray((const char*) &volumeHeader->FileSystemGuid, sizeof(EFI_GUID)) == EFI_FIRMWARE_FILE_SYSTEM2_GUID) {
|
|
||||||
// Code can be added here
|
|
||||||
}
|
|
||||||
// Other GUID
|
|
||||||
else {
|
|
||||||
//info = info.append(tr("File system: unknown\n"));
|
|
||||||
debug(tr("Unknown file system (%1)").arg(guidToQString(volumeHeader->FileSystemGuid)));
|
|
||||||
parseCurrentVolume = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check attributes
|
|
||||||
// Determine erase polarity
|
|
||||||
bool erasePolarity = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY;
|
|
||||||
|
|
||||||
// Check header checksum by recalculating it
|
|
||||||
if (!calculateChecksum16((UINT8*) volumeHeader, volumeHeader->HeaderLength)) {
|
|
||||||
debug(tr("Volume header checksum is invalid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for presence of extended header, only if header revision is not 1
|
|
||||||
UINT32 headerSize;
|
|
||||||
if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) {
|
|
||||||
EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER*) ((UINT8*) volumeHeader + volumeHeader->ExtHeaderOffset);
|
|
||||||
headerSize = volumeHeader->ExtHeaderOffset + extendedHeader->ExtHeaderSize;
|
|
||||||
} else {
|
|
||||||
headerSize = volumeHeader->HeaderLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adding tree item
|
|
||||||
QByteArray header = bios.mid(volumeIndex, headerSize);
|
|
||||||
QByteArray body = bios.mid(volumeIndex + headerSize, volumeHeader->FvLength - headerSize);
|
|
||||||
QModelIndex index = addTreeItem(VolumeItem, 0, header, body, parent);
|
|
||||||
|
|
||||||
// Parse volume
|
|
||||||
if (parseCurrentVolume) {
|
|
||||||
UINT32 result = parseVolume(bios.mid(volumeIndex + headerSize, volumeHeader->FvLength - headerSize), headerSize, volumeHeader->Revision, erasePolarity, index);
|
|
||||||
if (result)
|
|
||||||
debug(tr("Volume parsing failed (%1)").arg(result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
INT32 UEFITool::getNextVolumeIndex(const QByteArray & bios, INT32 volumeIndex)
|
|
||||||
{
|
|
||||||
if (volumeIndex < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
INT32 nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeIndex);
|
|
||||||
if (nextIndex < EFI_FV_SIGNATURE_OFFSET) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nextIndex - EFI_FV_SIGNATURE_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT32 UEFITool::getVolumeSize(const QByteArray & bios, INT32 volumeIndex)
|
|
||||||
{
|
|
||||||
// Populate volume header
|
|
||||||
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) (bios.constData() + volumeIndex);
|
|
||||||
|
|
||||||
// Check volume signature
|
|
||||||
if (QByteArray((const char*) &volumeHeader->Signature, sizeof(volumeHeader->Signature)) != EFI_FV_SIGNATURE)
|
|
||||||
return 0;
|
|
||||||
return volumeHeader->FvLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8 UEFITool::parseVolume(const QByteArray & volume, UINT32 volumeBase, UINT8 revision, bool erasePolarity, const QModelIndex & parent)
|
|
||||||
{
|
|
||||||
// Construct empty byte based on erasePolarity value
|
|
||||||
// Native char type is used because QByteArray.count() takes it
|
|
||||||
char empty = erasePolarity ? '\xFF' : '\x00';
|
|
||||||
|
|
||||||
// Search for and parse all files
|
|
||||||
INT32 fileIndex = 0;
|
|
||||||
while (fileIndex >= 0) {
|
|
||||||
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) (volume.constData() + fileIndex);
|
|
||||||
QByteArray file = volume.mid(fileIndex, uint24ToUint32(fileHeader->Size));
|
|
||||||
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
|
|
||||||
|
|
||||||
// Check file size to at least sizeof(EFI_FFS_FILE_HEADER)
|
|
||||||
if (file.size() < sizeof(EFI_FFS_FILE_HEADER))
|
|
||||||
{
|
|
||||||
debug(tr("File with invalid size"));
|
|
||||||
return ERR_INVALID_FILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are at empty space in the end of volume
|
|
||||||
if (header.count(empty) == header.size()) {
|
|
||||||
QByteArray body = volume.right(volume.size() - fileIndex);
|
|
||||||
addTreeItem(PaddingItem, 0, QByteArray(), body, parent);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check header checksum
|
|
||||||
QByteArray tempHeader = header;
|
|
||||||
EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*) (tempHeader.data());
|
|
||||||
tempFileHeader->IntegrityCheck.Checksum.Header = 0;
|
|
||||||
tempFileHeader->IntegrityCheck.Checksum.File = 0;
|
|
||||||
UINT8 calculated = calculateChecksum8((UINT8*) tempFileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1);
|
|
||||||
if (fileHeader->IntegrityCheck.Checksum.Header != calculated)
|
|
||||||
{
|
|
||||||
debug(tr("%1: stored header checksum %2 differs from calculated %3")
|
|
||||||
.arg(guidToQString(fileHeader->Name))
|
|
||||||
.arg(fileHeader->IntegrityCheck.Checksum.Header, 2, 16, QChar('0'))
|
|
||||||
.arg(calculated, 2, 16, QChar('0')));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check data checksum, if no tail was found
|
|
||||||
// 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(revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
|
|
||||||
bufferSize -= sizeof(UINT16);
|
|
||||||
calculated = calculateChecksum8((UINT8*)(file.constData() + sizeof(EFI_FFS_FILE_HEADER)), bufferSize);
|
|
||||||
if (fileHeader->IntegrityCheck.Checksum.File != calculated) {
|
|
||||||
debug(tr("%1: stored data checksum %2 differs from calculated %3")
|
|
||||||
.arg(guidToQString(fileHeader->Name))
|
|
||||||
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0'))
|
|
||||||
.arg(calculated, 2, 16, QChar('0')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Data checksum must be one of predefined values
|
|
||||||
else {
|
|
||||||
if (fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM &&fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2) {
|
|
||||||
debug(tr("%1: stored data checksum %2 differs from standard value")
|
|
||||||
.arg(guidToQString(fileHeader->Name))
|
|
||||||
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check file alignment
|
|
||||||
UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
|
|
||||||
UINT32 alignment = pow(2, alignmentPower);
|
|
||||||
if ((volumeBase + fileIndex + sizeof(EFI_FFS_FILE_HEADER)) % alignment) {
|
|
||||||
debug(tr("%1: unaligned file").arg(guidToQString(fileHeader->Name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get file body
|
|
||||||
QByteArray body = file.right(file.size() - sizeof(EFI_FFS_FILE_HEADER));
|
|
||||||
// For files in Revision 1 volumes, check for file tail presence
|
|
||||||
if (revision == 1 && fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
|
|
||||||
{
|
|
||||||
//Check file tail;
|
|
||||||
UINT16* tail = (UINT16*) body.right(sizeof(UINT16)).constData();
|
|
||||||
if (!fileHeader->IntegrityCheck.TailReference == *tail)
|
|
||||||
debug(tr("%1: file tail value %2 is not a bitwise not of %3 stored in file header")
|
|
||||||
.arg(guidToQString(fileHeader->Name))
|
|
||||||
.arg(*tail, 4, 16, QChar('0'))
|
|
||||||
.arg(fileHeader->IntegrityCheck.TailReference, 4, 16, QChar('0')));
|
|
||||||
|
|
||||||
// Remove tail from file body
|
|
||||||
body = body.left(body.size() - sizeof(UINT16));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse current file by default
|
|
||||||
bool parseCurrentFile = true;
|
|
||||||
// Raw files can hide volumes inside them
|
|
||||||
// So try to parse them as bios space
|
|
||||||
bool parseAsBios = false;
|
|
||||||
|
|
||||||
// Check file type
|
|
||||||
//!TODO: add more file specific checks
|
|
||||||
switch (fileHeader->Type)
|
|
||||||
{
|
|
||||||
case EFI_FV_FILETYPE_ALL:
|
|
||||||
parseAsBios = true;
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_RAW:
|
|
||||||
parseAsBios = true;
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_FREEFORM:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_SECURITY_CORE:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_PEI_CORE:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_DXE_CORE:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_PEIM:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_DRIVER:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_APPLICATION:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_SMM:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_COMBINED_SMM_DXE:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_SMM_CORE:
|
|
||||||
break;
|
|
||||||
case EFI_FV_FILETYPE_PAD:
|
|
||||||
parseCurrentFile = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
parseCurrentFile = false;
|
|
||||||
debug(tr("Unknown file type (%1)").arg(fileHeader->Type, 2, 16, QChar('0')));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check for empty file
|
|
||||||
if (body.count(empty) == body.size())
|
|
||||||
{
|
|
||||||
// No need to parse empty files
|
|
||||||
parseCurrentFile = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add tree item
|
|
||||||
QModelIndex index = addTreeItem(FileItem, fileHeader->Type, header, body, parent);
|
|
||||||
|
|
||||||
// Parse file
|
|
||||||
if (parseCurrentFile) {
|
|
||||||
if (parseAsBios) {
|
|
||||||
UINT32 result = parseBios(body, index);
|
|
||||||
if (result && result != ERR_VOLUMES_NOT_FOUND)
|
|
||||||
debug(tr("Parse file as BIOS failed (%1)").arg(result));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
UINT32 result = parseFile(body, revision, erasePolarity, index);
|
|
||||||
if (result)
|
|
||||||
debug(tr("Parse file as FFS failed (%1)").arg(result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to next file
|
|
||||||
fileIndex += file.size();
|
|
||||||
fileIndex = ALIGN8(fileIndex);
|
|
||||||
|
|
||||||
// Exit from loop if no files left
|
|
||||||
if (fileIndex >= volume.size())
|
|
||||||
fileIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT8 UEFITool::parseFile(const QByteArray & file, UINT8 revision, bool erasePolarity, const QModelIndex & parent)
|
|
||||||
{
|
|
||||||
// Search for and parse all sections
|
|
||||||
INT32 sectionIndex = 0;
|
|
||||||
while(sectionIndex >= 0)
|
|
||||||
{
|
|
||||||
EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*) (file.constData() + sectionIndex);
|
|
||||||
UINT32 sectionSize = uint24ToUint32(sectionHeader->Size);
|
|
||||||
|
|
||||||
// This declarations must be here because of the nature of switch statement
|
|
||||||
EFI_COMPRESSION_SECTION* compressedSectionHeader;
|
|
||||||
EFI_GUID_DEFINED_SECTION* guidDefinedSectionHeader;
|
|
||||||
QByteArray header;
|
|
||||||
QByteArray body;
|
|
||||||
UINT32 decompressedSize;
|
|
||||||
UINT32 scratchSize;
|
|
||||||
UINT8* decompressed;
|
|
||||||
UINT8* scratch;
|
|
||||||
VOID* data;
|
|
||||||
UINT32 dataSize;
|
|
||||||
QModelIndex index;
|
|
||||||
UINT32 result;
|
|
||||||
UINT32 shittySectionSize;
|
|
||||||
EFI_COMMON_SECTION_HEADER* shittySectionHeader;
|
|
||||||
|
|
||||||
switch (sectionHeader->Type)
|
|
||||||
{
|
|
||||||
// Encapsulated sections
|
|
||||||
case EFI_SECTION_COMPRESSION:
|
|
||||||
compressedSectionHeader = (EFI_COMPRESSION_SECTION*) sectionHeader;
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_COMPRESSION_SECTION));
|
|
||||||
|
|
||||||
// Try to decompress this section
|
|
||||||
switch (compressedSectionHeader->CompressionType)
|
|
||||||
{
|
|
||||||
case EFI_NOT_COMPRESSED:
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), compressedSectionHeader->UncompressedLength);
|
|
||||||
index = addTreeItem(SectionItem, CompressionSection, header, body, parent);
|
|
||||||
// Parse stored file
|
|
||||||
result = parseFile(body, revision, erasePolarity, index);
|
|
||||||
if (result)
|
|
||||||
debug(tr("Stored section can not be parsed as file (%1)").arg(result));
|
|
||||||
break;
|
|
||||||
case EFI_STANDARD_COMPRESSION:
|
|
||||||
//Must be Tiano for all revisions, needs checking
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), sectionSize - sizeof(EFI_COMPRESSION_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
|
|
||||||
// Get buffer sizes
|
|
||||||
data = (VOID*) (file.constData() + sectionIndex + sizeof(EFI_COMPRESSION_SECTION));
|
|
||||||
dataSize = uint24ToUint32(sectionHeader->Size) - sizeof(EFI_COMPRESSION_SECTION);
|
|
||||||
if (TianoGetInfo(data, dataSize, &decompressedSize, &scratchSize) != ERR_SUCCESS
|
|
||||||
|| decompressedSize != compressedSectionHeader->UncompressedLength)
|
|
||||||
debug(tr("TianoGetInfo failed"));
|
|
||||||
else {
|
|
||||||
decompressed = new UINT8[decompressedSize];
|
|
||||||
scratch = new UINT8[scratchSize];
|
|
||||||
// Decompress section data
|
|
||||||
if (TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize) != ERR_SUCCESS)
|
|
||||||
debug(tr("TianoDecompress failed"));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
body = QByteArray::fromRawData((const char*) decompressed, decompressedSize);
|
|
||||||
// Parse stored file
|
|
||||||
result = parseFile(body, revision, erasePolarity, index);
|
|
||||||
if (result)
|
|
||||||
debug(tr("Compressed section with Tiano compression can not be parsed as file (%1)").arg(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] decompressed;
|
|
||||||
delete[] scratch;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EFI_CUSTOMIZED_COMPRESSION:
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), sectionSize - sizeof(EFI_COMPRESSION_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
|
|
||||||
// Get buffer sizes
|
|
||||||
data = (VOID*) (file.constData() + sectionIndex + sizeof(EFI_COMPRESSION_SECTION));
|
|
||||||
dataSize = uint24ToUint32(sectionHeader->Size) - sizeof(EFI_COMPRESSION_SECTION);
|
|
||||||
if (LzmaGetInfo(data, dataSize, &decompressedSize) != ERR_SUCCESS
|
|
||||||
|| decompressedSize != compressedSectionHeader->UncompressedLength)
|
|
||||||
{
|
|
||||||
// Shitty file with a section header between COMPRESSED_SECTION_HEADER and LZMA_HEADER
|
|
||||||
// We must determine section header size by checking it's type before we can unpack that non-standard compressed section
|
|
||||||
shittySectionHeader = (EFI_COMMON_SECTION_HEADER*) data;
|
|
||||||
shittySectionSize = sizeOfSectionHeaderOfType(shittySectionHeader->Type);
|
|
||||||
data = (VOID*) (file.constData() + sectionIndex + sizeof(EFI_COMPRESSION_SECTION) + shittySectionSize);
|
|
||||||
dataSize = uint24ToUint32(sectionHeader->Size) - sizeof(EFI_COMPRESSION_SECTION) - shittySectionSize;
|
|
||||||
if (LzmaGetInfo(data, dataSize, &decompressedSize) != ERR_SUCCESS)
|
|
||||||
debug(tr("LzmaGetInfo failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
decompressed = new UINT8[decompressedSize];
|
|
||||||
|
|
||||||
// Decompress section data
|
|
||||||
if (LzmaDecompress(data, dataSize, decompressed) != ERR_SUCCESS)
|
|
||||||
debug(tr("LzmaDecompress failed"));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
body = QByteArray::fromRawData((const char*) decompressed, decompressedSize);
|
|
||||||
// Parse stored file
|
|
||||||
result = parseFile(body, revision, erasePolarity, index);
|
|
||||||
if (result)
|
|
||||||
debug(tr("Compressed section with LZMA compression can not be parsed as file (%1)").arg(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] decompressed;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_COMPRESSION_SECTION), sectionSize - sizeof(EFI_COMPRESSION_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
debug(tr("Compressed section with unknown compression type found (%1)").arg(compressedSectionHeader->CompressionType));
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_GUID_DEFINED:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_GUID_DEFINED_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_GUID_DEFINED_SECTION), sectionSize - sizeof(EFI_GUID_DEFINED_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
// Parse section body as file
|
|
||||||
guidDefinedSectionHeader = (EFI_GUID_DEFINED_SECTION*) (header.constData());
|
|
||||||
body = file.mid(sectionIndex + guidDefinedSectionHeader->DataOffset, sectionSize - guidDefinedSectionHeader->DataOffset);
|
|
||||||
result = parseFile(body, revision, erasePolarity, index);
|
|
||||||
if (result)
|
|
||||||
debug(tr("GUID defined section body can not be parsed as file (%1)").arg(result));
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_DISPOSABLE:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_DISPOSABLE_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_DISPOSABLE_SECTION), sectionSize - sizeof(EFI_DISPOSABLE_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
// Leaf sections
|
|
||||||
case EFI_SECTION_PE32:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_PE32_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_PE32_SECTION), sectionSize - sizeof(EFI_PE32_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_PIC:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_PIC_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_PIC_SECTION), sectionSize - sizeof(EFI_PIC_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_TE:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_TE_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_TE_SECTION), sectionSize - sizeof(EFI_TE_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_VERSION:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_VERSION_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_VERSION_SECTION), sectionSize - sizeof(EFI_VERSION_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_USER_INTERFACE:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_USER_INTERFACE_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_USER_INTERFACE_SECTION), sectionSize - sizeof(EFI_USER_INTERFACE_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_COMPATIBILITY16:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_COMPATIBILITY16_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_COMPATIBILITY16_SECTION), sectionSize - sizeof(EFI_COMPATIBILITY16_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION), sectionSize - sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
// Parse section body as BIOS space
|
|
||||||
result = parseBios(body, index);
|
|
||||||
if (result && result != ERR_VOLUMES_NOT_FOUND)
|
|
||||||
debug(tr("Firmware volume image can not be parsed (%1)").arg(result));
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION), sectionSize - sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_RAW:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_RAW_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_RAW_SECTION), sectionSize - sizeof(EFI_RAW_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
// Parse section body as BIOS space
|
|
||||||
result = parseBios(body, index);
|
|
||||||
if (result && result != ERR_VOLUMES_NOT_FOUND)
|
|
||||||
debug(tr("Raw section can not be parsed as BIOS (%1)").arg(result));
|
|
||||||
break;
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_DXE_DEPEX:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_DXE_DEPEX_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_DXE_DEPEX_SECTION), sectionSize - sizeof(EFI_DXE_DEPEX_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_PEI_DEPEX:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_PEI_DEPEX_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_PEI_DEPEX_SECTION), sectionSize - sizeof(EFI_PEI_DEPEX_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
case EFI_SECTION_SMM_DEPEX:
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_SMM_DEPEX_SECTION));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_SMM_DEPEX_SECTION), sectionSize - sizeof(EFI_SMM_DEPEX_SECTION));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
debug(tr("Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')));
|
|
||||||
header = file.mid(sectionIndex, sizeof(EFI_COMMON_SECTION_HEADER));
|
|
||||||
body = file.mid(sectionIndex + sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
|
|
||||||
index = addTreeItem(SectionItem, sectionHeader->Type, header, body, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to next section
|
|
||||||
sectionIndex += uint24ToUint32(sectionHeader->Size);
|
|
||||||
sectionIndex = ALIGN4(sectionIndex);
|
|
||||||
|
|
||||||
// Exit from loop if no sections left
|
|
||||||
if (sectionIndex >= file.size())
|
|
||||||
sectionIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
26
uefitool.h
26
uefitool.h
@ -26,17 +26,8 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "treemodel.h"
|
|
||||||
|
|
||||||
#include "basetypes.h"
|
#include "basetypes.h"
|
||||||
#include "descriptor.h"
|
#include "ffsengine.h"
|
||||||
#include "ffs.h"
|
|
||||||
#include "Tiano/EfiTianoCompress.h"
|
|
||||||
#include "Tiano/EfiTianoDecompress.h"
|
|
||||||
#include "LZMA/LzmaCompress.h"
|
|
||||||
#include "LZMA/LzmaDecompress.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class UEFITool;
|
class UEFITool;
|
||||||
@ -55,30 +46,19 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void init();
|
void init();
|
||||||
void openImageFile();
|
void openImageFile();
|
||||||
//void saveImageFile();
|
|
||||||
void populateUi(const QModelIndex ¤t/*, const QModelIndex &previous*/);
|
void populateUi(const QModelIndex ¤t/*, const QModelIndex &previous*/);
|
||||||
void resizeTreeViewColums(/*const QModelIndex &index*/);
|
void resizeTreeViewColums(/*const QModelIndex &index*/);
|
||||||
void saveAll();
|
void saveAll();
|
||||||
void saveBody();
|
void saveBody();
|
||||||
|
void saveUncompressedFile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::UEFITool * ui;
|
Ui::UEFITool * ui;
|
||||||
TreeModel * treeModel;
|
FfsEngine* ffsEngine;
|
||||||
QModelIndex currentIndex;
|
QModelIndex currentIndex;
|
||||||
|
|
||||||
void debug(const QString & text);
|
|
||||||
void dragEnterEvent(QDragEnterEvent* event);
|
void dragEnterEvent(QDragEnterEvent* event);
|
||||||
void dropEvent(QDropEvent* event);
|
void dropEvent(QDropEvent* event);
|
||||||
QModelIndex addTreeItem(UINT8 type, UINT8 subtype, const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(),
|
|
||||||
const QModelIndex & parent = QModelIndex());
|
|
||||||
|
|
||||||
UINT8 parseInputFile(const QByteArray & buffer);
|
|
||||||
UINT8* parseRegion(const QByteArray & flashImage, UINT8 regionSubtype, const UINT16 regionBase, const UINT16 regionLimit, QModelIndex & index);
|
|
||||||
UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex());
|
|
||||||
INT32 getNextVolumeIndex(const QByteArray & bios, INT32 volumeIndex = 0);
|
|
||||||
UINT32 getVolumeSize(const QByteArray & bios, INT32 volumeIndex);
|
|
||||||
UINT8 parseVolume(const QByteArray & volume, UINT32 volumeBase, UINT8 revision, bool erasePolarity, const QModelIndex & parent = QModelIndex());
|
|
||||||
UINT8 parseFile(const QByteArray & file, UINT8 revision, bool erasePolarity, const QModelIndex & parent = QModelIndex());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,6 +8,7 @@ SOURCES += main.cpp \
|
|||||||
uefitool.cpp \
|
uefitool.cpp \
|
||||||
descriptor.cpp \
|
descriptor.cpp \
|
||||||
ffs.cpp \
|
ffs.cpp \
|
||||||
|
ffsengine.cpp \
|
||||||
treeitem.cpp \
|
treeitem.cpp \
|
||||||
treemodel.cpp \
|
treemodel.cpp \
|
||||||
LZMA/LzmaCompress.c \
|
LZMA/LzmaCompress.c \
|
||||||
@ -21,7 +22,10 @@ SOURCES += main.cpp \
|
|||||||
HEADERS += uefitool.h \
|
HEADERS += uefitool.h \
|
||||||
basetypes.h \
|
basetypes.h \
|
||||||
descriptor.h \
|
descriptor.h \
|
||||||
|
gbe.h \
|
||||||
|
me.h \
|
||||||
ffs.h \
|
ffs.h \
|
||||||
|
ffsengine.h \
|
||||||
treeitem.h \
|
treeitem.h \
|
||||||
treeitemtypes.h \
|
treeitemtypes.h \
|
||||||
treemodel.h \
|
treemodel.h \
|
||||||
|
191
uefitool.ui
191
uefitool.ui
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>900</width>
|
<width>900</width>
|
||||||
<height>600</height>
|
<height>700</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>UEFITool 0.2.4</string>
|
<string>UEFITool 0.3.0</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralWidget">
|
<widget class="QWidget" name="centralWidget">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -30,7 +30,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="1" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QGroupBox" name="structureGroupBox">
|
<widget class="QGroupBox" name="structureGroupBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
@ -70,7 +70,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QGroupBox" name="infoGroupBox">
|
<widget class="QGroupBox" name="infoGroupBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
@ -88,6 +88,9 @@
|
|||||||
<string>Information</string>
|
<string>Information</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="infoEdit">
|
<widget class="QPlainTextEdit" name="infoEdit">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -119,30 +122,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="exportAllButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Export...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="exportBodyButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Export without header...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="1" column="0" colspan="2">
|
||||||
<widget class="QGroupBox" name="debugGroupBox">
|
<widget class="QGroupBox" name="debugGroupBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
@ -194,16 +177,160 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QPushButton" name="fromFileButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Open BIOS image file...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar"/>
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
|
<widget class="QToolBar" name="toolBar">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>toolBar</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionOpenImageFile"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionExtract"/>
|
||||||
|
<addaction name="actionExtractBody"/>
|
||||||
|
<addaction name="actionExtractUncompressed"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionInsertBefore"/>
|
||||||
|
<addaction name="actionInsertAfter"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionReplace"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionDelete"/>
|
||||||
|
<addaction name="actionReplaceWithPadding"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
</widget>
|
||||||
|
<action name="actionInsertAfter">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Insert after</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Insert an object from file after selected object</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+I</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionInsertBefore">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Insert before</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Insert an object from file before selected object</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+I</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReplace">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Replace</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Replace selected object with an object from file</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+R</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExtract">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Extract</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Extract selected object to file</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+E</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExtractBody">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Extract body</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Extract selected object without header to file</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+E</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExtractUncompressed">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Extract uncompressed</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Extract selected FFS file uncompressing it </string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Alt+E</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete selected object</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReplaceWithPadding">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Replace with padding</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Delete an object by replacing it with padding</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOpenImageFile">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open image file</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Open image file</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+O</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
Loading…
Reference in New Issue
Block a user