mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-21 23:48:22 +08:00
UT NE A19
Thanks to lordkag for #41: - improved parsing of Intel flash descriptor - improved detection of Tiano/EFI 1.1 compression type - added 2 UEFI capsule GUIDs used by Lenovo - solved potential crash on very low memory available - UEFIExtract and UEFIFind update to include the latest parser changes
This commit is contained in:
parent
61a1e98403
commit
4cf6b4f37b
@ -71,7 +71,7 @@ STATUS FfsDumper::recursiveDump(const QModelIndex & index, const QString & path,
|
||||
QString info = tr("Type: %1\nSubtype: %2\n%3%4")
|
||||
.arg(itemTypeToQString(model->type(index)))
|
||||
.arg(itemSubtypeToQString(model->type(index), model->subtype(index)))
|
||||
.arg(model->text(index).isEmpty() ? "" : tr("Text: %1\n").arg(model->text(index)))
|
||||
.arg(model->text(index).isEmpty() ? tr("") : tr("Text: %1\n").arg(model->text(index)))
|
||||
.arg(model->info(index));
|
||||
file.setFileName(tr("%1/info.txt").arg(path));
|
||||
if (!file.open(QFile::Text | QFile::WriteOnly))
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* uefiextract_main.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -49,7 +49,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
TreeModel model;
|
||||
FfsParser ffsParser(&model);
|
||||
STATUS result = ffsParser.parseImageFile(buffer, model.index(0, 0));
|
||||
STATUS result = ffsParser.parse(buffer);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
@ -75,8 +75,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "UEFIExtract 0.10.6" << std::endl << std::endl
|
||||
<< "Usage: uefiextract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl
|
||||
std::cout << "UEFIExtract 0.10.7" << std::endl << std::endl
|
||||
<< "Usage: UEFIExtract imagefile [FileGUID_1 FileGUID_2 ... FileGUID_31]" << std::endl
|
||||
<< "Return value is a bit mask where 0 at position N means that file with GUID_N was found and unpacked, 1 otherwise" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* uefifind.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -46,7 +46,7 @@ STATUS UEFIFind::init(const QString & path)
|
||||
QByteArray buffer = inputFile.readAll();
|
||||
inputFile.close();
|
||||
|
||||
result = ffsParser->parseImageFile(buffer, model->index(0,0));
|
||||
result = ffsParser->parse(buffer);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* uefifind_main.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -148,9 +148,9 @@ int main(int argc, char *argv[])
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
std::cout << "UEFIFind 0.10.4.1" << std::endl << std::endl <<
|
||||
"Usage: uefifind {header | body | all} {list | count} pattern imagefile" << std::endl <<
|
||||
" or uefifind file patternsfile imagefile" << std::endl;
|
||||
std::cout << "UEFIFind 0.10.5" << std::endl << std::endl <<
|
||||
"Usage: UEFIFind {header | body | all} {list | count} pattern imagefile" << std::endl <<
|
||||
" or UEFIFind file patternsfile imagefile" << std::endl;
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* uefitool.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -17,7 +17,7 @@
|
||||
UEFITool::UEFITool(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::UEFITool),
|
||||
version(tr("0.30.0_alpha18"))
|
||||
version(tr("0.30.0_alpha19"))
|
||||
{
|
||||
clipboard = QApplication::clipboard();
|
||||
|
||||
@ -566,7 +566,7 @@ void UEFITool::extract(const UINT8 mode)
|
||||
void UEFITool::about()
|
||||
{
|
||||
QMessageBox::about(this, tr("About UEFITool"), tr(
|
||||
"Copyright (c) 2015, Nikolaj Schlej aka <b>CodeRush</b>.<br>"
|
||||
"Copyright (c) 2016, Nikolaj Schlej aka <b>CodeRush</b>.<br>"
|
||||
"Program icon made by <a href=https://www.behance.net/alzhidkov>Alexander Zhidkov</a>.<br><br>"
|
||||
"The program is dedicated to <b>RevoGirl</b>. Rest in peace, young genius.<br><br>"
|
||||
"The program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License.<br>"
|
||||
@ -657,7 +657,7 @@ void UEFITool::openImageFile(QString path)
|
||||
init();
|
||||
setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName()));
|
||||
|
||||
UINT8 result = ffsParser->parseImageFile(buffer, model->index(0,0));
|
||||
UINT8 result = ffsParser->parse(buffer);
|
||||
showParserMessages();
|
||||
if (result) {
|
||||
QMessageBox::critical(this, tr("Image parsing failed"), errorCodeToQString(result), QMessageBox::Ok);
|
||||
|
@ -506,6 +506,7 @@ Returns:
|
||||
UINT32 i;
|
||||
|
||||
mText = malloc (WNDSIZ * 2 + MAXMATCH);
|
||||
if (!mText) return EFI_OUT_OF_RESOURCES;
|
||||
for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) {
|
||||
mText[i] = 0;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* basetypes.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -93,12 +93,13 @@ typedef UINT8 STATUS;
|
||||
#define EFI_ERROR(X) (X)
|
||||
|
||||
// Compression algorithms
|
||||
#define COMPRESSION_ALGORITHM_UNKNOWN 0
|
||||
#define COMPRESSION_ALGORITHM_NONE 1
|
||||
#define COMPRESSION_ALGORITHM_EFI11 2
|
||||
#define COMPRESSION_ALGORITHM_TIANO 3
|
||||
#define COMPRESSION_ALGORITHM_LZMA 4
|
||||
#define COMPRESSION_ALGORITHM_IMLZMA 5
|
||||
#define COMPRESSION_ALGORITHM_UNKNOWN 0
|
||||
#define COMPRESSION_ALGORITHM_NONE 1
|
||||
#define COMPRESSION_ALGORITHM_EFI11 2
|
||||
#define COMPRESSION_ALGORITHM_TIANO 3
|
||||
#define COMPRESSION_ALGORITHM_UNDECIDED 4
|
||||
#define COMPRESSION_ALGORITHM_LZMA 5
|
||||
#define COMPRESSION_ALGORITHM_IMLZMA 6
|
||||
|
||||
// Item create modes
|
||||
#define CREATE_MODE_APPEND 0
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* descriptor.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -21,7 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
// Flash descriptor header
|
||||
typedef struct _FLASH_DESCRIPTOR_HEADER {
|
||||
UINT8 FfVector[16]; // Must be 16 0xFFs
|
||||
UINT8 ReservedVector[16]; // Reserved for ARM ResetVector, 0xFFs on x86/x86-64 machines
|
||||
UINT32 Signature; // 0x0FF0A55A
|
||||
} FLASH_DESCRIPTOR_HEADER;
|
||||
|
||||
@ -98,7 +98,7 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION {
|
||||
UINT8 InvalidInstruction2; //
|
||||
UINT8 InvalidInstruction3; //
|
||||
UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000
|
||||
UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen
|
||||
UINT16 : 16;
|
||||
} FLASH_DESCRIPTOR_COMPONENT_SECTION;
|
||||
|
||||
// Region section
|
||||
@ -115,16 +115,16 @@ typedef struct _FLASH_DESCRIPTOR_REGION_SECTION {
|
||||
UINT16 GbeLimit; //
|
||||
UINT16 PdrBase; // PDR
|
||||
UINT16 PdrLimit; //
|
||||
UINT16 Region5Base; // Reserved region
|
||||
UINT16 Region5Limit; //
|
||||
UINT16 Region6Base; // Reserved region
|
||||
UINT16 Region6Limit; //
|
||||
UINT16 Region7Base; // Reserved region
|
||||
UINT16 Region7Limit; //
|
||||
UINT16 Reserved1Base; // Reserved1
|
||||
UINT16 Reserved1Limit; //
|
||||
UINT16 Reserved2Base; // Reserved2
|
||||
UINT16 Reserved2Limit; //
|
||||
UINT16 Reserved3Base; // Reserved3
|
||||
UINT16 Reserved3Limit; //
|
||||
UINT16 EcBase; // EC
|
||||
UINT16 EcLimit; //
|
||||
UINT16 Region9Base; // Reserved region
|
||||
UINT16 Region9Limit; //
|
||||
UINT16 Reserved4Base; // Reserved4
|
||||
UINT16 Reserved4Limit; //
|
||||
} FLASH_DESCRIPTOR_REGION_SECTION;
|
||||
|
||||
// Master section
|
||||
|
10
common/ffs.h
10
common/ffs.h
@ -1,6 +1,6 @@
|
||||
/* ffs.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -53,6 +53,14 @@ const QByteArray EFI_CAPSULE_GUID
|
||||
const QByteArray INTEL_CAPSULE_GUID
|
||||
("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16);
|
||||
|
||||
// Lenovo capsule GUID
|
||||
const QByteArray LENOVO_CAPSULE_GUID
|
||||
("\xD3\xAF\x0B\xE2\x14\x99\x4F\x4F\x95\x37\x31\x29\xE0\x90\xEB\x3C", 16);
|
||||
|
||||
// Another Lenovo capsule GUID
|
||||
const QByteArray LENOVO2_CAPSULE_GUID
|
||||
("\x76\xFE\xB5\x25\x43\x82\x5C\x4A\xA9\xBD\x7E\xE3\x24\x61\x98\xB5", 16);
|
||||
|
||||
// Toshiba EFI Capsule header
|
||||
typedef struct _TOSHIBA_CAPSULE_HEADER {
|
||||
EFI_GUID CapsuleGuid;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* fssbuilder.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -19,11 +19,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include <QString>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include "../common/basetypes.h"
|
||||
#include "../common/treemodel.h"
|
||||
#include "../common/descriptor.h"
|
||||
#include "../common/ffs.h"
|
||||
#include "../common/utility.h"
|
||||
#include "basetypes.h"
|
||||
#include "treemodel.h"
|
||||
#include "descriptor.h"
|
||||
#include "ffs.h"
|
||||
#include "utility.h"
|
||||
|
||||
class FfsBuilder : public QObject
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* ffsparser.cpp
|
||||
/* ffsparser.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -10,16 +10,18 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
*/
|
||||
|
||||
#include "ffsparser.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "ffsparser.h"
|
||||
#include "types.h"
|
||||
#include "treemodel.h"
|
||||
#include "descriptor.h"
|
||||
#include "ffs.h"
|
||||
#include "gbe.h"
|
||||
#include "me.h"
|
||||
#include "fit.h"
|
||||
// Region info structure definition
|
||||
struct REGION_INFO {
|
||||
UINT32 offset;
|
||||
UINT32 length;
|
||||
UINT8 type;
|
||||
QByteArray data;
|
||||
friend bool operator< (const REGION_INFO & lhs, const REGION_INFO & rhs){ return lhs.offset < rhs.offset; }
|
||||
};
|
||||
|
||||
FfsParser::FfsParser(TreeModel* treeModel, QObject *parent)
|
||||
: QObject(parent), model(treeModel), capsuleOffsetFixup(0)
|
||||
@ -45,47 +47,53 @@ void FfsParser::clearMessages()
|
||||
messagesVector.clear();
|
||||
}
|
||||
|
||||
BOOLEAN FfsParser::hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2)
|
||||
// Firmware image parsing functions
|
||||
STATUS FfsParser::parse(const QByteArray & buffer)
|
||||
{
|
||||
if (begin1 < begin2 && begin2 < end1)
|
||||
return TRUE;
|
||||
if (begin1 < end2 && end2 < end1)
|
||||
return TRUE;
|
||||
if (begin2 < begin1 && begin1 < end2)
|
||||
return TRUE;
|
||||
if (begin2 < end1 && end1 < end2)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
QModelIndex root;
|
||||
STATUS result = performFirstPass(buffer, root);
|
||||
addOffsetsRecursive(root);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (lastVtf.isValid()) {
|
||||
result = performSecondPass(root);
|
||||
}
|
||||
else {
|
||||
msg(tr("parse: not a single Volume Top File is found, the image may be corrupted"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Firmware image parsing functions
|
||||
STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex & root)
|
||||
STATUS FfsParser::performFirstPass(const QByteArray & buffer, QModelIndex & index)
|
||||
{
|
||||
// Reset capsule offset fixeup value
|
||||
// Reset capsule offset fixup value
|
||||
capsuleOffsetFixup = 0;
|
||||
|
||||
// Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER
|
||||
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
|
||||
msg(tr("parseImageFile: image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
||||
msg(tr("performFirstPass: image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
QModelIndex index;
|
||||
UINT32 capsuleHeaderSize = 0;
|
||||
// Check buffer for being normal EFI capsule header
|
||||
if (buffer.startsWith(EFI_CAPSULE_GUID)
|
||||
|| buffer.startsWith(INTEL_CAPSULE_GUID)) {
|
||||
|| buffer.startsWith(INTEL_CAPSULE_GUID)
|
||||
|| buffer.startsWith(LENOVO_CAPSULE_GUID)
|
||||
|| buffer.startsWith(LENOVO2_CAPSULE_GUID)) {
|
||||
// Get info
|
||||
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
|
||||
|
||||
// Check sanity of HeaderSize and CapsuleImageSize values
|
||||
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->CapsuleImageSize) {
|
||||
msg(tr("parseImageFile: UEFI capsule header size of %1h (%2) bytes is invalid")
|
||||
msg(tr("performFirstPass: UEFI capsule header size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
if (capsuleHeader->CapsuleImageSize == 0 || capsuleHeader->CapsuleImageSize > (UINT32)buffer.size()) {
|
||||
msg(tr("parseImageFile: UEFI capsule image size of %1h (%2) bytes is invalid")
|
||||
msg(tr("performFirstPass: UEFI capsule image size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->CapsuleImageSize).arg(capsuleHeader->CapsuleImageSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
@ -105,7 +113,7 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
capsuleOffsetFixup = capsuleHeaderSize;
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, TRUE, QByteArray(), root);
|
||||
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, true);
|
||||
}
|
||||
// Check buffer for being Toshiba capsule header
|
||||
else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) {
|
||||
@ -114,12 +122,12 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
|
||||
// Check sanity of HeaderSize and FullSize values
|
||||
if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)buffer.size() || capsuleHeader->HeaderSize > capsuleHeader->FullSize) {
|
||||
msg(tr("parseImageFile: Toshiba capsule header size of %1h (%2) bytes is invalid")
|
||||
msg(tr("performFirstPass: Toshiba capsule header size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
if (capsuleHeader->FullSize == 0 || capsuleHeader->FullSize > (UINT32)buffer.size()) {
|
||||
msg(tr("parseImageFile: Toshiba capsule full size of %1h (%2) bytes is invalid")
|
||||
msg(tr("performFirstPass: Toshiba capsule full size of %1h (%2) bytes is invalid")
|
||||
.hexarg(capsuleHeader->FullSize).arg(capsuleHeader->FullSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
@ -139,14 +147,14 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
capsuleOffsetFixup = capsuleHeaderSize;
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, name, QString(), info, header, body, TRUE, QByteArray(), root);
|
||||
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, name, QString(), info, header, body, true);
|
||||
}
|
||||
// Check buffer for being extended Aptio signed capsule header
|
||||
// Check buffer for being extended Aptio capsule header
|
||||
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
|
||||
bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID);
|
||||
|
||||
if ((UINT32)buffer.size() <= sizeof(APTIO_CAPSULE_HEADER)) {
|
||||
msg(tr("parseImageFile: AMI capsule image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(APTIO_CAPSULE_HEADER)).arg(sizeof(APTIO_CAPSULE_HEADER)));
|
||||
msg(tr("performFirstPass: AMI capsule image file is smaller than minimum size of %1h (%2) bytes").hexarg(sizeof(APTIO_CAPSULE_HEADER)).arg(sizeof(APTIO_CAPSULE_HEADER)));
|
||||
return ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
@ -155,11 +163,11 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
|
||||
// Check sanity of RomImageOffset and CapsuleImageSize values
|
||||
if (capsuleHeader->RomImageOffset == 0 || capsuleHeader->RomImageOffset > (UINT32)buffer.size() || capsuleHeader->RomImageOffset > capsuleHeader->CapsuleHeader.CapsuleImageSize) {
|
||||
msg(tr("parseImageFile: AMI capsule image offset of %1h (%2) bytes is invalid").hexarg(capsuleHeader->RomImageOffset).arg(capsuleHeader->RomImageOffset));
|
||||
msg(tr("performFirstPass: AMI capsule image offset of %1h (%2) bytes is invalid").hexarg(capsuleHeader->RomImageOffset).arg(capsuleHeader->RomImageOffset));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
if (capsuleHeader->CapsuleHeader.CapsuleImageSize == 0 || capsuleHeader->CapsuleHeader.CapsuleImageSize > (UINT32)buffer.size()) {
|
||||
msg(tr("parseImageFile: AMI capsule image size of %1h (%2) bytes is invalid").hexarg(capsuleHeader->CapsuleHeader.CapsuleImageSize).arg(capsuleHeader->CapsuleHeader.CapsuleImageSize));
|
||||
msg(tr("performFirstPass: AMI capsule image size of %1h (%2) bytes is invalid").hexarg(capsuleHeader->CapsuleHeader.CapsuleImageSize).arg(capsuleHeader->CapsuleHeader.CapsuleImageSize));
|
||||
return ERR_INVALID_CAPSULE;
|
||||
}
|
||||
|
||||
@ -178,17 +186,13 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
capsuleOffsetFixup = capsuleHeaderSize;
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, QString(), info, header, body, TRUE, QByteArray(), root);
|
||||
index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, QString(), info, header, body, true);
|
||||
|
||||
// Show message about possible Aptio signature break
|
||||
if (signedCapsule) {
|
||||
msg(tr("parseImageFile: Aptio capsule signature may become invalid after image modifications"), index);
|
||||
msg(tr("performFirstPass: Aptio capsule signature may become invalid after image modifications"), index);
|
||||
}
|
||||
}
|
||||
// Other cases
|
||||
else {
|
||||
index = root;
|
||||
}
|
||||
|
||||
// Skip capsule header to have flash chip image
|
||||
QByteArray flashImage = buffer.mid(capsuleHeaderSize);
|
||||
@ -202,13 +206,16 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
// Parse as Intel image
|
||||
QModelIndex imageIndex;
|
||||
result = parseIntelImage(flashImage, capsuleHeaderSize, index, imageIndex);
|
||||
if (result != ERR_INVALID_FLASH_DESCRIPTOR)
|
||||
if (result != ERR_INVALID_FLASH_DESCRIPTOR) {
|
||||
if (!index.isValid())
|
||||
index = imageIndex;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Get info
|
||||
QString name = tr("UEFI image");
|
||||
QString info = tr("Full size: %2h (%3)").hexarg(flashImage.size()).arg(flashImage.size());
|
||||
QString info = tr("Full size: %1h (%2)").hexarg(flashImage.size()).arg(flashImage.size());
|
||||
|
||||
// Construct parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
@ -219,21 +226,9 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex &
|
||||
|
||||
// Parse the image
|
||||
result = parseRawArea(flashImage, biosIndex);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// Add offsets
|
||||
addOffsetsRecursive(index);
|
||||
|
||||
// Check if the last VTF is found
|
||||
if (!lastVtf.isValid()) {
|
||||
msg(tr("parseImageFile: not a single Volume Top File is found, the image may be corrupted"), biosIndex);
|
||||
}
|
||||
else {
|
||||
return performSecondPass(biosIndex);
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
if (!index.isValid())
|
||||
index = biosIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
@ -247,8 +242,6 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
|
||||
// Store the beginning of descriptor as descriptor base address
|
||||
const UINT8* descriptor = (const UINT8*)intelImage.constData();
|
||||
UINT32 descriptorBegin = 0;
|
||||
UINT32 descriptorEnd = FLASH_DESCRIPTOR_SIZE;
|
||||
|
||||
// Check for buffer size to be greater or equal to descriptor region size
|
||||
if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) {
|
||||
@ -258,7 +251,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
|
||||
// Parse descriptor map
|
||||
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
|
||||
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
|
||||
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
|
||||
|
||||
// Check sanity of base values
|
||||
if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||
@ -291,43 +284,47 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// Regions
|
||||
QVector<REGION_INFO> regions;
|
||||
|
||||
// ME region
|
||||
QByteArray me;
|
||||
UINT32 meBegin = 0;
|
||||
UINT32 meEnd = 0;
|
||||
REGION_INFO me;
|
||||
me.type = Subtypes::MeRegion;
|
||||
me.offset = 0;
|
||||
me.length = 0;
|
||||
if (regionSection->MeLimit) {
|
||||
meBegin = calculateRegionOffset(regionSection->MeBase);
|
||||
meEnd = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit);
|
||||
me = intelImage.mid(meBegin, meEnd);
|
||||
meEnd += meBegin;
|
||||
me.offset = calculateRegionOffset(regionSection->MeBase);
|
||||
me.length = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit);
|
||||
me.data = intelImage.mid(me.offset, me.length);
|
||||
regions.append(me);
|
||||
}
|
||||
|
||||
// BIOS region
|
||||
QByteArray bios;
|
||||
UINT32 biosBegin = 0;
|
||||
UINT32 biosEnd = 0;
|
||||
REGION_INFO bios;
|
||||
bios.type = Subtypes::BiosRegion;
|
||||
bios.offset = 0;
|
||||
bios.length = 0;
|
||||
if (regionSection->BiosLimit) {
|
||||
biosBegin = calculateRegionOffset(regionSection->BiosBase);
|
||||
biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit);
|
||||
bios.offset = calculateRegionOffset(regionSection->BiosBase);
|
||||
bios.length = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit);
|
||||
|
||||
// Check for Gigabyte specific descriptor map
|
||||
if (biosEnd - biosBegin == (UINT32)intelImage.size()) {
|
||||
if (!meEnd) {
|
||||
if (bios.length == (UINT32)intelImage.size()) {
|
||||
if (!me.offset) {
|
||||
msg(tr("parseIntelImage: can't determine BIOS region start from Gigabyte-specific descriptor"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
biosBegin = meEnd;
|
||||
bios = intelImage.mid(biosBegin, biosEnd);
|
||||
// biosEnd will point to the end of the image file
|
||||
// it may be wrong, but it's pretty hard to detect a padding after BIOS region
|
||||
// with malformed descriptor
|
||||
// Use ME region end as BIOS region offset
|
||||
bios.offset = me.offset + me.length;
|
||||
bios.length = (UINT32)intelImage.size() - bios.offset;
|
||||
bios.data = intelImage.mid(bios.offset, bios.length);
|
||||
}
|
||||
// Normal descriptor map
|
||||
else {
|
||||
bios = intelImage.mid(biosBegin, biosEnd);
|
||||
// Calculate biosEnd
|
||||
biosEnd += biosBegin;
|
||||
bios.data = intelImage.mid(bios.offset, bios.length);
|
||||
}
|
||||
|
||||
regions.append(bios);
|
||||
}
|
||||
else {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor"));
|
||||
@ -335,107 +332,148 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
}
|
||||
|
||||
// GbE region
|
||||
QByteArray gbe;
|
||||
UINT32 gbeBegin = 0;
|
||||
UINT32 gbeEnd = 0;
|
||||
REGION_INFO gbe;
|
||||
gbe.type = Subtypes::GbeRegion;
|
||||
gbe.offset = 0;
|
||||
gbe.length = 0;
|
||||
if (regionSection->GbeLimit) {
|
||||
gbeBegin = calculateRegionOffset(regionSection->GbeBase);
|
||||
gbeEnd = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit);
|
||||
gbe = intelImage.mid(gbeBegin, gbeEnd);
|
||||
gbeEnd += gbeBegin;
|
||||
gbe.offset = calculateRegionOffset(regionSection->GbeBase);
|
||||
gbe.length = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit);
|
||||
gbe.data = intelImage.mid(gbe.offset, gbe.length);
|
||||
regions.append(gbe);
|
||||
}
|
||||
|
||||
// PDR region
|
||||
QByteArray pdr;
|
||||
UINT32 pdrBegin = 0;
|
||||
UINT32 pdrEnd = 0;
|
||||
REGION_INFO pdr;
|
||||
pdr.type = Subtypes::PdrRegion;
|
||||
pdr.offset = 0;
|
||||
pdr.length = 0;
|
||||
if (regionSection->PdrLimit) {
|
||||
pdrBegin = calculateRegionOffset(regionSection->PdrBase);
|
||||
pdrEnd = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit);
|
||||
pdr = intelImage.mid(pdrBegin, pdrEnd);
|
||||
pdrEnd += pdrBegin;
|
||||
pdr.offset = calculateRegionOffset(regionSection->PdrBase);
|
||||
pdr.length = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit);
|
||||
pdr.data = intelImage.mid(pdr.offset, pdr.length);
|
||||
regions.append(pdr);
|
||||
}
|
||||
|
||||
// Reserved1 region
|
||||
REGION_INFO reserved1;
|
||||
reserved1.type = Subtypes::Reserved1Region;
|
||||
reserved1.offset = 0;
|
||||
reserved1.length = 0;
|
||||
if (regionSection->Reserved1Limit && regionSection->Reserved1Base != 0xFFFF && regionSection->Reserved1Limit != 0xFFFF) {
|
||||
reserved1.offset = calculateRegionOffset(regionSection->Reserved1Base);
|
||||
reserved1.length = calculateRegionSize(regionSection->Reserved1Base, regionSection->Reserved1Limit);
|
||||
reserved1.data = intelImage.mid(reserved1.offset, reserved1.length);
|
||||
regions.append(reserved1);
|
||||
}
|
||||
|
||||
// Reserved2 region
|
||||
REGION_INFO reserved2;
|
||||
reserved2.type = Subtypes::Reserved2Region;
|
||||
reserved2.offset = 0;
|
||||
reserved2.length = 0;
|
||||
if (regionSection->Reserved2Limit && regionSection->Reserved2Base != 0xFFFF && regionSection->Reserved2Limit != 0xFFFF) {
|
||||
reserved2.offset = calculateRegionOffset(regionSection->Reserved2Base);
|
||||
reserved2.length = calculateRegionSize(regionSection->Reserved2Base, regionSection->Reserved2Limit);
|
||||
reserved2.data = intelImage.mid(reserved2.offset, reserved2.length);
|
||||
regions.append(reserved2);
|
||||
}
|
||||
|
||||
// Reserved3 region
|
||||
REGION_INFO reserved3;
|
||||
reserved3.type = Subtypes::Reserved3Region;
|
||||
reserved3.offset = 0;
|
||||
reserved3.length = 0;
|
||||
|
||||
// EC region
|
||||
QByteArray ec;
|
||||
UINT32 ecBegin = 0;
|
||||
UINT32 ecEnd = 0;
|
||||
REGION_INFO ec;
|
||||
ec.type = Subtypes::EcRegion;
|
||||
ec.offset = 0;
|
||||
ec.length = 0;
|
||||
|
||||
// Reserved4 region
|
||||
REGION_INFO reserved4;
|
||||
reserved3.type = Subtypes::Reserved4Region;
|
||||
reserved4.offset = 0;
|
||||
reserved4.length = 0;
|
||||
|
||||
// Check for EC and reserved region 4 only for v2 descriptor
|
||||
if (descriptorVersion == 2) {
|
||||
if (regionSection->Reserved3Limit) {
|
||||
reserved3.offset = calculateRegionOffset(regionSection->Reserved3Base);
|
||||
reserved3.length = calculateRegionSize(regionSection->Reserved3Base, regionSection->Reserved3Limit);
|
||||
reserved3.data = intelImage.mid(reserved3.offset, reserved3.length);
|
||||
regions.append(reserved3);
|
||||
}
|
||||
|
||||
if (regionSection->EcLimit) {
|
||||
pdrBegin = calculateRegionOffset(regionSection->EcBase);
|
||||
pdrEnd = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit);
|
||||
pdr = intelImage.mid(ecBegin, ecEnd);
|
||||
ecEnd += ecBegin;
|
||||
ec.offset = calculateRegionOffset(regionSection->EcBase);
|
||||
ec.length = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit);
|
||||
ec.data = intelImage.mid(ec.offset, ec.length);
|
||||
regions.append(ec);
|
||||
}
|
||||
|
||||
if (regionSection->Reserved4Limit) {
|
||||
reserved4.offset = calculateRegionOffset(regionSection->Reserved4Base);
|
||||
reserved4.length = calculateRegionSize(regionSection->Reserved4Base, regionSection->Reserved4Limit);
|
||||
reserved4.data = intelImage.mid(reserved4.offset, reserved4.length);
|
||||
regions.append(reserved4);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for intersections between regions
|
||||
// Descriptor
|
||||
if (hasIntersection(descriptorBegin, descriptorEnd, gbeBegin, gbeEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with GbE region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (hasIntersection(descriptorBegin, descriptorEnd, meBegin, meEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with ME region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (hasIntersection(descriptorBegin, descriptorEnd, biosBegin, biosEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with BIOS region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (hasIntersection(descriptorBegin, descriptorEnd, pdrBegin, pdrEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with PDR region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorVersion == 2 && hasIntersection(descriptorBegin, descriptorEnd, ecBegin, ecEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with EC region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// GbE
|
||||
if (hasIntersection(gbeBegin, gbeEnd, meBegin, meEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with ME region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (hasIntersection(gbeBegin, gbeEnd, biosBegin, biosEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with BIOS region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (hasIntersection(gbeBegin, gbeEnd, pdrBegin, pdrEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with PDR region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorVersion == 2 && hasIntersection(gbeBegin, gbeEnd, ecBegin, ecEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with EC region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// ME
|
||||
if (hasIntersection(meBegin, meEnd, biosBegin, biosEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with BIOS region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (hasIntersection(meBegin, meEnd, pdrBegin, pdrEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with PDR region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorVersion == 2 && hasIntersection(meBegin, meEnd, ecBegin, ecEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with EC region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// BIOS
|
||||
if (hasIntersection(biosBegin, biosEnd, pdrBegin, pdrEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with PDR region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorVersion == 2 && hasIntersection(biosBegin, biosEnd, ecBegin, ecEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with EC region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// PDR
|
||||
if (descriptorVersion == 2 && hasIntersection(pdrBegin, pdrEnd, ecBegin, ecEnd)) {
|
||||
msg(tr("parseIntelImage: descriptor parsing failed, PDR region has intersection with EC region"));
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Sort regions in ascending order
|
||||
qSort(regions);
|
||||
|
||||
// Check for intersections and paddings between regions
|
||||
REGION_INFO region;
|
||||
// Check intersection with the descriptor
|
||||
if (regions.first().offset < FLASH_DESCRIPTOR_SIZE) {
|
||||
msg(tr("parseIntelImage: %1 region has intersection with flash descriptor").arg(itemSubtypeToQString(Types::Region, regions.first().type)), index);
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Check for padding between descriptor and the first region
|
||||
else if (regions.first().offset > FLASH_DESCRIPTOR_SIZE) {
|
||||
region.offset = FLASH_DESCRIPTOR_SIZE;
|
||||
region.length = regions.first().offset - FLASH_DESCRIPTOR_SIZE;
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
regions.prepend(region);
|
||||
}
|
||||
// Check for intersections/paddings between regions
|
||||
for (int i = 1; i < regions.count(); i++) {
|
||||
UINT32 previousRegionEnd = regions[i-1].offset + regions[i-1].length;
|
||||
// Check that current region is fully present in the image
|
||||
if (regions[i].offset + regions[i].length > (UINT32)intelImage.size()) {
|
||||
msg(tr("parseIntelImage: %1 region is located outside of opened image, if your system uses dual-chip storage, please append another part to the opened image")
|
||||
.arg(itemSubtypeToQString(Types::Region, regions[i].type)), index);
|
||||
return ERR_TRUNCATED_IMAGE;
|
||||
}
|
||||
|
||||
// Check for intersection with previous region
|
||||
if (regions[i].offset < previousRegionEnd) {
|
||||
msg(tr("parseIntelImage: %1 region has intersection with %2 region")
|
||||
.arg(itemSubtypeToQString(Types::Region, regions[i].type))
|
||||
.arg(itemSubtypeToQString(Types::Region, regions[i-1].type)), index);
|
||||
return ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Check for padding between current and previous regions
|
||||
else if (regions[i].offset > previousRegionEnd) {
|
||||
region.offset = previousRegionEnd;
|
||||
region.length = regions[i].offset - previousRegionEnd;
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
regions.insert(i - 1, region);
|
||||
}
|
||||
}
|
||||
// Check for padding after the last region
|
||||
if (regions.last().offset + regions.last().length < (UINT32)intelImage.size()) {
|
||||
region.offset = regions.last().offset + regions.last().length;
|
||||
region.length = intelImage.size() - region.offset;
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
regions.append(region);
|
||||
}
|
||||
|
||||
// Region map is consistent
|
||||
|
||||
// Intel image
|
||||
@ -459,24 +497,11 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
QByteArray body = intelImage.left(FLASH_DESCRIPTOR_SIZE);
|
||||
name = tr("Descriptor region");
|
||||
info = tr("Full size: %1h (%2)").hexarg(FLASH_DESCRIPTOR_SIZE).arg(FLASH_DESCRIPTOR_SIZE);
|
||||
|
||||
// Check regions presence once again
|
||||
QVector<UINT32> offsets;
|
||||
if (regionSection->GbeLimit) {
|
||||
offsets.append(gbeBegin);
|
||||
info += tr("\nGbE region offset: %1h").hexarg(gbeBegin + parentOffset);
|
||||
}
|
||||
if (regionSection->MeLimit) {
|
||||
offsets.append(meBegin);
|
||||
info += tr("\nME region offset: %1h").hexarg(meBegin + parentOffset);
|
||||
}
|
||||
if (regionSection->BiosLimit) {
|
||||
offsets.append(biosBegin);
|
||||
info += tr("\nBIOS region offset: %1h").hexarg(biosBegin + parentOffset);
|
||||
}
|
||||
if (regionSection->PdrLimit) {
|
||||
offsets.append(pdrBegin);
|
||||
info += tr("\nPDR region offset: %1h").hexarg(pdrBegin + parentOffset);
|
||||
|
||||
// Add offsets of actual regions
|
||||
for (int i = 0; i < regions.count(); i++) {
|
||||
if (regions[i].type != Subtypes::ZeroPadding && regions[i].type != Subtypes::OnePadding && regions[i].type != Subtypes::DataPadding)
|
||||
info += tr("\n%1 region offset: %2h").arg(itemSubtypeToQString(Types::Region, regions[i].type)).hexarg(regions[i].offset + parentOffset);
|
||||
}
|
||||
|
||||
// Region access settings
|
||||
@ -555,93 +580,63 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
|
||||
}
|
||||
|
||||
// Add descriptor tree item
|
||||
model->addItem(Types::Region, Subtypes::DescriptorRegion, name, QString(), info, QByteArray(), body, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
// Sort regions in ascending order
|
||||
qSort(offsets);
|
||||
|
||||
QModelIndex regionIndex = model->addItem(Types::Region, Subtypes::DescriptorRegion, name, QString(), info, QByteArray(), body, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
// Parse regions
|
||||
UINT8 result = 0;
|
||||
for (int i = 0; i < offsets.count(); i++) {
|
||||
// Parse GbE region
|
||||
if (offsets.at(i) == gbeBegin) {
|
||||
QModelIndex gbeIndex;
|
||||
result = parseGbeRegion(gbe, gbeBegin, index, gbeIndex);
|
||||
UINT8 result = ERR_SUCCESS;
|
||||
UINT8 parseResult = ERR_SUCCESS;
|
||||
Q_FOREACH(region, regions) {
|
||||
switch (region.type) {
|
||||
case Subtypes::BiosRegion:
|
||||
result = parseBiosRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::MeRegion:
|
||||
result = parseMeRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::GbeRegion:
|
||||
result = parseGbeRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::PdrRegion:
|
||||
result = parsePdrRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::Reserved1Region:
|
||||
case Subtypes::Reserved2Region:
|
||||
case Subtypes::Reserved3Region:
|
||||
case Subtypes::EcRegion:
|
||||
case Subtypes::Reserved4Region:
|
||||
result = parseGeneralRegion(region.type, region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::ZeroPadding:
|
||||
case Subtypes::OnePadding:
|
||||
case Subtypes::DataPadding: {
|
||||
// Add padding between regions
|
||||
QByteArray padding = intelImage.mid(region.offset, region.length);
|
||||
|
||||
// Get parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
|
||||
// Get info
|
||||
name = tr("Padding");
|
||||
info = tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset = parentOffset + region.offset;
|
||||
|
||||
// Add tree item
|
||||
regionIndex = model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
result = ERR_SUCCESS;
|
||||
} break;
|
||||
default:
|
||||
msg(tr("parseIntelImage: region of unknown type found"), index);
|
||||
result = ERR_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Parse ME region
|
||||
else if (offsets.at(i) == meBegin) {
|
||||
QModelIndex meIndex;
|
||||
result = parseMeRegion(me, meBegin, index, meIndex);
|
||||
}
|
||||
// Parse BIOS region
|
||||
else if (offsets.at(i) == biosBegin) {
|
||||
QModelIndex biosIndex;
|
||||
result = parseBiosRegion(bios, biosBegin, index, biosIndex);
|
||||
}
|
||||
// Parse PDR region
|
||||
else if (offsets.at(i) == pdrBegin) {
|
||||
QModelIndex pdrIndex;
|
||||
result = parsePdrRegion(pdr, pdrBegin, index, pdrIndex);
|
||||
}
|
||||
// Parse EC region
|
||||
else if (descriptorVersion == 2 && offsets.at(i) == ecBegin) {
|
||||
QModelIndex ecIndex;
|
||||
result = parseEcRegion(ec, ecBegin, index, ecIndex);
|
||||
}
|
||||
if (result)
|
||||
return result;
|
||||
// Store the first failed result as a final result
|
||||
if (!parseResult && result)
|
||||
parseResult = result;
|
||||
}
|
||||
|
||||
// Add the data after the last region as padding
|
||||
UINT32 IntelDataEnd = 0;
|
||||
UINT32 LastRegionOffset = offsets.last();
|
||||
if (LastRegionOffset == gbeBegin)
|
||||
IntelDataEnd = gbeEnd;
|
||||
else if (LastRegionOffset == meBegin)
|
||||
IntelDataEnd = meEnd;
|
||||
else if (LastRegionOffset == biosBegin)
|
||||
IntelDataEnd = biosEnd;
|
||||
else if (LastRegionOffset == pdrBegin)
|
||||
IntelDataEnd = pdrEnd;
|
||||
else if (descriptorVersion == 2 && LastRegionOffset == ecBegin)
|
||||
IntelDataEnd = ecEnd;
|
||||
|
||||
if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated
|
||||
msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged")
|
||||
.hexarg(intelImage.size()).arg(intelImage.size())
|
||||
.hexarg(IntelDataEnd).arg(IntelDataEnd), index);
|
||||
return ERR_TRUNCATED_IMAGE;
|
||||
}
|
||||
else if (IntelDataEnd < (UINT32)intelImage.size()) { // Insert padding
|
||||
QByteArray padding = intelImage.mid(IntelDataEnd);
|
||||
|
||||
// Get parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(index);
|
||||
|
||||
// Get info
|
||||
name = tr("Padding");
|
||||
info = tr("Full size: %1h (%2)")
|
||||
.hexarg(padding.size()).arg(padding.size());
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset = IntelDataEnd;
|
||||
|
||||
// Add tree item
|
||||
model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
}
|
||||
|
||||
// Add offsets
|
||||
addOffsetsRecursive(index);
|
||||
|
||||
// Check if the last VTF is found
|
||||
if (!lastVtf.isValid()) {
|
||||
msg(tr("parseIntelImage: not a single Volume Top File is found, the image may be corrupted"), index);
|
||||
}
|
||||
else {
|
||||
return performSecondPass(index);
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
return parseResult;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
@ -774,25 +769,25 @@ STATUS FfsParser::parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffs
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseEcRegion(const QByteArray & ec, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
STATUS FfsParser::parseGeneralRegion(const UINT8 subtype, const QByteArray & region, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (ec.isEmpty())
|
||||
if (region.isEmpty())
|
||||
return ERR_EMPTY_REGION;
|
||||
|
||||
// Get parent's parsing data
|
||||
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
|
||||
|
||||
// Get info
|
||||
QString name = tr("EC region");
|
||||
QString name = tr("%1 region").arg(itemSubtypeToQString(Types::Region, subtype));
|
||||
QString info = tr("Full size: %1h (%2)").
|
||||
hexarg(ec.size()).arg(ec.size());
|
||||
hexarg(region.size()).arg(region.size());
|
||||
|
||||
// Construct parsing data
|
||||
pdata.offset += parentOffset;
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(Types::Region, Subtypes::EcRegion, name, QString(), info, QByteArray(), ec, TRUE, parsingDataToQByteArray(pdata), parent);
|
||||
index = model->addItem(Types::Region, subtype, name, QString(), info, QByteArray(), region, TRUE, parsingDataToQByteArray(pdata), parent);
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
@ -1190,7 +1185,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset)
|
||||
STATUS FfsParser::findNextVolume(const QModelIndex & index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset)
|
||||
{
|
||||
int nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset);
|
||||
if (nextIndex < EFI_FV_SIGNATURE_OFFSET)
|
||||
@ -1745,7 +1740,7 @@ STATUS FfsParser::parsePadFileBody(const QModelIndex & index)
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex & index)
|
||||
STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex & index, const bool preparse)
|
||||
{
|
||||
// Sanity check
|
||||
if (!index.isValid())
|
||||
@ -1759,6 +1754,7 @@ STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex &
|
||||
UINT32 headerSize = model->header(index).size();
|
||||
UINT32 sectionOffset = 0;
|
||||
|
||||
STATUS result = ERR_SUCCESS;
|
||||
while (sectionOffset < bodySize) {
|
||||
// Get section size
|
||||
UINT32 sectionSize = getSectionSize(sections, sectionOffset, pdata.ffsVersion);
|
||||
@ -1773,27 +1769,36 @@ STATUS FfsParser::parseSections(const QByteArray & sections, const QModelIndex &
|
||||
// Constuct parsing data
|
||||
pdata.offset += headerSize + sectionOffset;
|
||||
|
||||
// Add tree item
|
||||
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
// Show message
|
||||
msg(tr("parseSections: non-UEFI data found in sections area"), dataIndex);
|
||||
// Final parsing
|
||||
if (!preparse) {
|
||||
// Add tree item
|
||||
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, tr("Non-UEFI data"), "", info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index);
|
||||
|
||||
// Show message
|
||||
msg(tr("parseSections: non-UEFI data found in sections area"), dataIndex);
|
||||
}
|
||||
// Preparsing
|
||||
else {
|
||||
return ERR_INVALID_SECTION;
|
||||
}
|
||||
break; // Exit from parsing loop
|
||||
}
|
||||
|
||||
// Parse section header
|
||||
QModelIndex sectionIndex;
|
||||
STATUS result = parseSectionHeader(sections.mid(sectionOffset, sectionSize), headerSize + sectionOffset, index, sectionIndex);
|
||||
if (result)
|
||||
msg(tr("parseSections: section header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
|
||||
result = parseSectionHeader(sections.mid(sectionOffset, sectionSize), headerSize + sectionOffset, index, sectionIndex);
|
||||
if (result) {
|
||||
if (!preparse)
|
||||
msg(tr("parseSections: section header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
else
|
||||
return ERR_INVALID_SECTION;
|
||||
}
|
||||
// Move to next section
|
||||
sectionOffset += sectionSize;
|
||||
sectionOffset = ALIGN4(sectionOffset);
|
||||
}
|
||||
|
||||
//Parse bodies
|
||||
//Parse bodies, will be skipped on preparse phase
|
||||
for (int i = 0; i < model->rowCount(index); i++) {
|
||||
QModelIndex current = index.child(i, 0);
|
||||
switch (model->type(current)) {
|
||||
@ -2013,7 +2018,7 @@ STATUS FfsParser::parseGuidedSectionHeader(const QByteArray & section, const UIN
|
||||
|
||||
// Check certificate type
|
||||
if (certType == WIN_CERT_TYPE_EFI_GUID) {
|
||||
additionalInfo += tr("\nCertificate type: UEFI").hexarg2(certType, 4);
|
||||
additionalInfo += tr("\nCertificate type: UEFI");
|
||||
|
||||
// Get certificate GUID
|
||||
const WIN_CERTIFICATE_UEFI_GUID* winCertificateUefiGuid = (const WIN_CERTIFICATE_UEFI_GUID*)(section.constData() + nextHeaderOffset);
|
||||
@ -2256,7 +2261,8 @@ STATUS FfsParser::parseCompressedSectionBody(const QModelIndex & index)
|
||||
|
||||
// Decompress section
|
||||
QByteArray decompressed;
|
||||
STATUS result = decompress(model->body(index), algorithm, decompressed);
|
||||
QByteArray efiDecompressed;
|
||||
STATUS result = decompress(model->body(index), algorithm, decompressed, efiDecompressed);
|
||||
if (result) {
|
||||
msg(tr("parseCompressedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return ERR_SUCCESS;
|
||||
@ -2272,6 +2278,22 @@ STATUS FfsParser::parseCompressedSectionBody(const QModelIndex & index)
|
||||
model->addInfo(index, tr("\nActual decompressed size: %1h (%2)").hexarg(decompressed.size()).arg(decompressed.size()));
|
||||
}
|
||||
|
||||
// Check for undecided compression algorithm, this is a special case
|
||||
if (algorithm == COMPRESSION_ALGORITHM_UNDECIDED) {
|
||||
// Try preparse of sections decompressed with Tiano algorithm
|
||||
if (ERR_SUCCESS == parseSections(decompressed, index, true)) {
|
||||
algorithm = COMPRESSION_ALGORITHM_TIANO;
|
||||
}
|
||||
// Try preparse of sections decompressed with EFI 1.1 algorithm
|
||||
else if (ERR_SUCCESS == parseSections(efiDecompressed, index, true)) {
|
||||
algorithm = COMPRESSION_ALGORITHM_EFI11;
|
||||
decompressed = efiDecompressed;
|
||||
}
|
||||
else {
|
||||
msg(tr("parseCompressedSectionBody: can't guess the correct decompression algorithm, both preparse steps are failed"), index);
|
||||
}
|
||||
}
|
||||
|
||||
// Add info
|
||||
model->addInfo(index, tr("\nCompression algorithm: %1").arg(compressionTypeToQString(algorithm)));
|
||||
|
||||
@ -2302,24 +2324,33 @@ STATUS FfsParser::parseGuidedSectionBody(const QModelIndex & index)
|
||||
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE;
|
||||
// Tiano compressed section
|
||||
if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
|
||||
QByteArray efiDecompressed;
|
||||
algorithm = EFI_STANDARD_COMPRESSION;
|
||||
STATUS result = decompress(model->body(index), algorithm, processed);
|
||||
STATUS result = decompress(model->body(index), algorithm, processed, efiDecompressed);
|
||||
if (result) {
|
||||
parseCurrentSection = false;
|
||||
msg(tr("parseGuidedSectionBody: decompression failed with error \"%1\"").arg(errorCodeToQString(result)), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (algorithm == COMPRESSION_ALGORITHM_TIANO) {
|
||||
info += tr("\nCompression algorithm: Tiano");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
// Check for undecided compression algorithm, this is a special case
|
||||
if (algorithm == COMPRESSION_ALGORITHM_UNDECIDED) {
|
||||
// Try preparse of sections decompressed with Tiano algorithm
|
||||
if (ERR_SUCCESS == parseSections(processed, index, true)) {
|
||||
algorithm = COMPRESSION_ALGORITHM_TIANO;
|
||||
}
|
||||
// Try preparse of sections decompressed with EFI 1.1 algorithm
|
||||
else if (ERR_SUCCESS == parseSections(efiDecompressed, index, true)) {
|
||||
algorithm = COMPRESSION_ALGORITHM_EFI11;
|
||||
processed = efiDecompressed;
|
||||
}
|
||||
else {
|
||||
msg(tr("parseGuidedSectionBody: can't guess the correct decompression algorithm, both preparse steps are failed"), index);
|
||||
}
|
||||
}
|
||||
else if (algorithm == COMPRESSION_ALGORITHM_EFI11) {
|
||||
info += tr("\nCompression algorithm: EFI 1.1");
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
else
|
||||
info += tr("\nCompression type: unknown");
|
||||
|
||||
info += tr("\nCompression algorithm: %1").arg(compressionTypeToQString(algorithm));
|
||||
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
|
||||
}
|
||||
// LZMA compressed section
|
||||
else if (QByteArray((const char*)&guid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* ffsparser.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -26,6 +26,13 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include "utility.h"
|
||||
#include "peimage.h"
|
||||
#include "parsingdata.h"
|
||||
#include "types.h"
|
||||
#include "treemodel.h"
|
||||
#include "descriptor.h"
|
||||
#include "ffs.h"
|
||||
#include "gbe.h"
|
||||
#include "me.h"
|
||||
#include "fit.h"
|
||||
|
||||
class TreeModel;
|
||||
|
||||
@ -44,7 +51,7 @@ public:
|
||||
void clearMessages();
|
||||
|
||||
// Firmware image parsing
|
||||
STATUS parseImageFile(const QByteArray & imageFile, const QModelIndex & index);
|
||||
STATUS parse(const QByteArray &buffer);
|
||||
STATUS parseRawArea(const QByteArray & data, const QModelIndex & index);
|
||||
STATUS parseVolumeHeader(const QByteArray & volume, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
STATUS parseVolumeBody(const QModelIndex & index);
|
||||
@ -67,11 +74,11 @@ private:
|
||||
STATUS parseMeRegion(const QByteArray & me, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
STATUS parseBiosRegion(const QByteArray & bios, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
STATUS parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
STATUS parseEcRegion(const QByteArray & ec, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
STATUS parseGeneralRegion(const UINT8 subtype, const QByteArray & region, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
|
||||
STATUS parsePadFileBody(const QModelIndex & index);
|
||||
STATUS parseVolumeNonUefiData(const QByteArray & data, const UINT32 parentOffset, const QModelIndex & index);
|
||||
STATUS parseSections(const QByteArray & sections, const QModelIndex & index);
|
||||
STATUS parseSections(const QByteArray & sections, const QModelIndex & index, const bool preparse = false);
|
||||
|
||||
STATUS parseCommonSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
STATUS parseCompressedSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
|
||||
@ -91,21 +98,18 @@ private:
|
||||
|
||||
UINT8 getPaddingType(const QByteArray & padding);
|
||||
STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed);
|
||||
STATUS findNextVolume(const QModelIndex index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
|
||||
STATUS findNextVolume(const QModelIndex & index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
|
||||
STATUS getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize);
|
||||
UINT32 getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion);
|
||||
UINT32 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion);
|
||||
|
||||
STATUS performFirstPass(const QByteArray & imageFile, QModelIndex & index);
|
||||
STATUS performSecondPass(const QModelIndex & index);
|
||||
STATUS addOffsetsRecursive(const QModelIndex & index);
|
||||
STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff);
|
||||
|
||||
// Internal operations
|
||||
BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
|
||||
|
||||
// Message helper
|
||||
void msg(const QString & message, const QModelIndex &index = QModelIndex());
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* types.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -21,16 +21,24 @@ QString regionTypeToQString(const UINT8 type)
|
||||
{
|
||||
case Subtypes::DescriptorRegion:
|
||||
return QObject::tr("Descriptor");
|
||||
case Subtypes::GbeRegion:
|
||||
return QObject::tr("GbE");
|
||||
case Subtypes::MeRegion:
|
||||
return QObject::tr("ME");
|
||||
case Subtypes::BiosRegion:
|
||||
return QObject::tr("BIOS");
|
||||
case Subtypes::MeRegion:
|
||||
return QObject::tr("ME");
|
||||
case Subtypes::GbeRegion:
|
||||
return QObject::tr("GbE");
|
||||
case Subtypes::PdrRegion:
|
||||
return QObject::tr("PDR");
|
||||
case Subtypes::Reserved1Region:
|
||||
return QObject::tr("Reserved1");
|
||||
case Subtypes::Reserved2Region:
|
||||
return QObject::tr("Reserved2");
|
||||
case Subtypes::Reserved3Region:
|
||||
return QObject::tr("Reserved3");
|
||||
case Subtypes::EcRegion:
|
||||
return QObject::tr("EC");
|
||||
case Subtypes::Reserved4Region:
|
||||
return QObject::tr("Reserved4");
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
};
|
||||
@ -124,6 +132,8 @@ QString compressionTypeToQString(const UINT8 algorithm)
|
||||
return QObject::tr("EFI 1.1");
|
||||
case COMPRESSION_ALGORITHM_TIANO:
|
||||
return QObject::tr("Tiano");
|
||||
case COMPRESSION_ALGORITHM_UNDECIDED:
|
||||
return QObject::tr("Undecided Tiano/EFI 1.1");
|
||||
case COMPRESSION_ALGORITHM_LZMA:
|
||||
return QObject::tr("LZMA");
|
||||
case COMPRESSION_ALGORITHM_IMLZMA:
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* types.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -66,12 +66,16 @@ namespace Subtypes {
|
||||
};
|
||||
|
||||
enum RegionSubtypes {
|
||||
DescriptorRegion = 100,
|
||||
GbeRegion,
|
||||
MeRegion,
|
||||
DescriptorRegion = 0,
|
||||
BiosRegion,
|
||||
MeRegion,
|
||||
GbeRegion,
|
||||
PdrRegion,
|
||||
EcRegion
|
||||
Reserved1Region,
|
||||
Reserved2Region,
|
||||
Reserved3Region,
|
||||
EcRegion,
|
||||
Reserved4Region
|
||||
};
|
||||
|
||||
enum PaddingSubtypes {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* utility.cpp
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -151,11 +151,12 @@ UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length)
|
||||
}
|
||||
|
||||
// Compression routines
|
||||
STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArray & decompressedData)
|
||||
STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArray & decompressedData, QByteArray & efiDecompressedData)
|
||||
{
|
||||
const UINT8* data;
|
||||
UINT32 dataSize;
|
||||
UINT8* decompressed;
|
||||
UINT8* efiDecompressed;
|
||||
UINT32 decompressedSize = 0;
|
||||
UINT8* scratch;
|
||||
UINT32 scratchSize = 0;
|
||||
@ -167,7 +168,7 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
|
||||
decompressedData = compressedData;
|
||||
algorithm = COMPRESSION_ALGORITHM_NONE;
|
||||
return ERR_SUCCESS;
|
||||
case EFI_STANDARD_COMPRESSION:
|
||||
case EFI_STANDARD_COMPRESSION: {
|
||||
// Set default algorithm to unknown
|
||||
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
||||
|
||||
@ -185,34 +186,45 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
|
||||
return ERR_STANDARD_DECOMPRESSION_FAILED;
|
||||
|
||||
// Allocate memory
|
||||
try {
|
||||
decompressed = new UINT8[decompressedSize];
|
||||
scratch = new UINT8[scratchSize];
|
||||
}
|
||||
catch (std::bad_alloc) {
|
||||
decompressed = (UINT8*)malloc(decompressedSize);
|
||||
efiDecompressed = (UINT8*)malloc(decompressedSize);
|
||||
scratch = (UINT8*)malloc(scratchSize);
|
||||
if (!decompressed || !efiDecompressed || !scratch) {
|
||||
if (decompressed) free(decompressed);
|
||||
if (efiDecompressed) free(efiDecompressed);
|
||||
if (scratch) free(scratch);
|
||||
return ERR_STANDARD_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
// Decompress section data
|
||||
// Decompress section data using both algorithms
|
||||
STATUS result = ERR_SUCCESS;
|
||||
// Try Tiano
|
||||
STATUS TianoResult = TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize);
|
||||
// Try EFI 1.1
|
||||
STATUS EfiResult = EfiDecompress(data, dataSize, efiDecompressed, decompressedSize, scratch, scratchSize);
|
||||
|
||||
//TODO: separate EFI1.1 from Tiano another way
|
||||
// Try Tiano decompression first
|
||||
if (ERR_SUCCESS != TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
|
||||
// Not Tiano, try EFI 1.1
|
||||
if (ERR_SUCCESS != EfiDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
|
||||
delete[] decompressed;
|
||||
delete[] scratch;
|
||||
return ERR_STANDARD_DECOMPRESSION_FAILED;
|
||||
}
|
||||
else algorithm = COMPRESSION_ALGORITHM_EFI11;
|
||||
if (EfiResult == ERR_SUCCESS && TianoResult == ERR_SUCCESS) { // Both decompressions are OK
|
||||
algorithm = COMPRESSION_ALGORITHM_UNDECIDED;
|
||||
decompressedData = QByteArray((const char*)decompressed, decompressedSize);
|
||||
efiDecompressedData = QByteArray((const char*)efiDecompressed, decompressedSize);
|
||||
}
|
||||
else if (TianoResult == ERR_SUCCESS) { // Only Tiano is OK
|
||||
algorithm = COMPRESSION_ALGORITHM_TIANO;
|
||||
decompressedData = QByteArray((const char*)decompressed, decompressedSize);
|
||||
}
|
||||
else if (EfiResult == ERR_SUCCESS) { // Only EFI 1.1 is OK
|
||||
algorithm = COMPRESSION_ALGORITHM_EFI11;
|
||||
decompressedData = QByteArray((const char*)efiDecompressed, decompressedSize);
|
||||
}
|
||||
else { // Both decompressions failed
|
||||
result = ERR_STANDARD_DECOMPRESSION_FAILED;
|
||||
}
|
||||
else algorithm = COMPRESSION_ALGORITHM_TIANO;
|
||||
|
||||
decompressedData = QByteArray((const char*)decompressed, decompressedSize);
|
||||
|
||||
delete[] decompressed;
|
||||
delete[] scratch;
|
||||
return ERR_SUCCESS;
|
||||
free(decompressed);
|
||||
free(efiDecompressed);
|
||||
free(scratch);
|
||||
return result;
|
||||
}
|
||||
case EFI_CUSTOMIZED_COMPRESSION:
|
||||
// Set default algorithm to unknown
|
||||
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
||||
@ -226,10 +238,8 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
|
||||
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
|
||||
|
||||
// Allocate memory
|
||||
try {
|
||||
decompressed = new UINT8[decompressedSize];
|
||||
}
|
||||
catch (std::bad_alloc) {
|
||||
decompressed = (UINT8*)malloc(decompressedSize);
|
||||
if (!decompressed) {
|
||||
return ERR_STANDARD_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
@ -241,13 +251,13 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
|
||||
|
||||
// Get info again
|
||||
if (ERR_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) {
|
||||
delete[] decompressed;
|
||||
free(decompressed);
|
||||
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
// Decompress section data again
|
||||
if (ERR_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
|
||||
delete[] decompressed;
|
||||
free(decompressed);
|
||||
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED;
|
||||
}
|
||||
else {
|
||||
@ -260,7 +270,7 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
|
||||
decompressedData = QByteArray((const char*)decompressed, decompressedSize);
|
||||
}
|
||||
|
||||
delete[] decompressed;
|
||||
free(decompressed);
|
||||
return ERR_SUCCESS;
|
||||
default:
|
||||
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* utility.h
|
||||
|
||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
||||
Copyright (c) 2016, 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
|
||||
@ -29,7 +29,7 @@ QByteArray parsingDataToQByteArray(const PARSING_DATA & pdata);
|
||||
extern QString errorCodeToQString(UINT8 errorCode);
|
||||
|
||||
// Decompression routine
|
||||
extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByteArray & decompressed);
|
||||
extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByteArray & decompressed, QByteArray & efiDecompressed = QByteArray());
|
||||
|
||||
// Compression routine
|
||||
//STATUS compress(const QByteArray & decompressed, QByteArray & compressed, const UINT8 & algorithm);
|
||||
|
Loading…
Reference in New Issue
Block a user