From 4006954bc13cdf800296f286bde7a62bb1ec9d05 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 28 Aug 2022 12:47:01 +0200 Subject: [PATCH] Downcast all qtsizetype to UINT32 manually, apply consistent identation --- UEFITool/ffsfinder.cpp | 330 +++--- UEFITool/guidlineedit.cpp | 41 +- UEFITool/hexspinbox.cpp | 22 +- UEFITool/hexviewdialog.cpp | 22 +- UEFITool/searchdialog.cpp | 26 +- UEFITool/uefitool.cpp | 960 ++++++++-------- UEFITool/uefitool_main.cpp | 28 +- common/descriptor.cpp | 422 +++---- common/ffs.cpp | 50 +- common/ffsbuilder.cpp | 146 +-- common/ffsops.cpp | 46 +- common/ffsparser.cpp | 2222 ++++++++++++++++++------------------ common/ffsreport.cpp | 48 +- common/ffsutils.cpp | 42 +- common/guiddatabase.cpp | 48 +- common/meparser.cpp | 128 +-- common/nvram.cpp | 48 +- common/nvramparser.cpp | 932 +++++++-------- common/peimage.cpp | 54 +- common/treeitem.cpp | 84 +- common/treemodel.cpp | 174 +-- common/types.cpp | 344 +++--- common/uinttypes.h | 1 - common/ustring.cpp | 42 +- common/utility.cpp | 536 ++++----- 25 files changed, 3398 insertions(+), 3398 deletions(-) diff --git a/UEFITool/ffsfinder.cpp b/UEFITool/ffsfinder.cpp index b84589b..2a632b5 100644 --- a/UEFITool/ffsfinder.cpp +++ b/UEFITool/ffsfinder.cpp @@ -1,15 +1,15 @@ /* fssfinder.cpp - -Copyright (c) 2015, 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2015, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "ffsfinder.h" @@ -22,22 +22,22 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray & hexPattern, const UINT8 mode) { //TODO: use FfsUtils. - + if (!index.isValid()) return U_SUCCESS; - + if (hexPattern.isEmpty()) return U_INVALID_PARAMETER; - + // Check for "all substrings" pattern if (hexPattern.count('.') == hexPattern.length()) return U_SUCCESS; - + bool hasChildren = (model->rowCount(index) > 0); for (int i = 0; i < model->rowCount(index); i++) { findHexPattern(index.model()->index(i, index.column(), index), hexPattern, mode); } - + UByteArray data; if (hasChildren) { if (mode == SEARCH_MODE_HEADER) @@ -53,177 +53,177 @@ USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray & else data = model->header(index) + model->body(index); } - + UString hexBody = UString(data.toHex()); #if QT_VERSION_MAJOR >= 6 QRegularExpression regexp = QRegularExpression(UString(hexPattern)); regexp.setPatternOptions((QRegularExpression::PatternOptions)0x1); QRegularExpressionMatch regexpmatch; - + INT32 offset = 0; while ((offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset, ®expmatch)) != -1) { #else - QRegExp regexp = QRegExp(UString(hexPattern), Qt::CaseInsensitive); - - INT32 offset = regexp.indexIn(hexBody); - - while (offset >= 0) { + QRegExp regexp = QRegExp(UString(hexPattern), Qt::CaseInsensitive); + + INT32 offset = regexp.indexIn(hexBody); + + while (offset >= 0) { #endif - - if (offset % 2 == 0) { - // For patterns that cross header|body boundary, skip patterns entirely located in body, since - // children search above has already found them. - if (!(hasChildren && mode == SEARCH_MODE_ALL && offset/2 >= model->header(index).size())) { - msg(UString("Hex pattern \"") + UString(hexPattern) + + if (offset % 2 == 0) { + // For patterns that cross header|body boundary, skip patterns entirely located in body, since + // children search above has already found them. + if (!(hasChildren && mode == SEARCH_MODE_ALL && offset/2 >= model->header(index).size())) { + msg(UString("Hex pattern \"") + UString(hexPattern) + + UString("\" found as \"") + hexBody.mid(offset, hexPattern.length()).toUpper() + + UString("\" in ") + model->name(model->parent(index)) + + UString("/") + model->name(index) + + usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", offset / 2), + index); + } + } + +#if QT_VERSION_MAJOR >= 6 + offset += 1; +#else + offset = regexp.indexIn(hexBody, offset + 1); +#endif + } + + return U_SUCCESS; + } + + USTATUS FfsFinder::findGuidPattern(const UModelIndex & index, const UByteArray & guidPattern, const UINT8 mode) + { + if (guidPattern.isEmpty()) + return U_INVALID_PARAMETER; + + if (!index.isValid()) + return U_SUCCESS; + + bool hasChildren = (model->rowCount(index) > 0); + for (int i = 0; i < model->rowCount(index); i++) { + findGuidPattern(index.model()->index(i, index.column(), index), guidPattern, mode); + } + + UByteArray data; + if (hasChildren) { + if (mode != SEARCH_MODE_BODY) + data = model->header(index); + } + else { + if (mode == SEARCH_MODE_HEADER) + data.append(model->header(index)); + else if (mode == SEARCH_MODE_BODY) + data.append(model->body(index)); + else + data.append(model->header(index)).append(model->body(index)); + } + + UString hexBody = UString(data.toHex()); + QList list = guidPattern.split('-'); + if (list.count() != 5) + return U_INVALID_PARAMETER; + + UByteArray hexPattern; + // Reverse first GUID block + hexPattern.append(list.at(0).mid(6, 2)); + hexPattern.append(list.at(0).mid(4, 2)); + hexPattern.append(list.at(0).mid(2, 2)); + hexPattern.append(list.at(0).mid(0, 2)); + // Reverse second GUID block + hexPattern.append(list.at(1).mid(2, 2)); + hexPattern.append(list.at(1).mid(0, 2)); + // Reverse third GUID block + hexPattern.append(list.at(2).mid(2, 2)); + hexPattern.append(list.at(2).mid(0, 2)); + // Append fourth and fifth GUID blocks as is + hexPattern.append(list.at(3)).append(list.at(4)); + + // Check for "all substrings" pattern + if (hexPattern.count('.') == hexPattern.length()) + return U_SUCCESS; + +#if QT_VERSION_MAJOR >= 6 + QRegularExpression regexp((QString)UString(hexPattern)); + regexp.setPatternOptions((QRegularExpression::PatternOptions)0x1); + QRegularExpressionMatch regexpmatch; + + INT32 offset = 0; + offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset, ®expmatch); +#else + QRegExp regexp(UString(hexPattern), Qt::CaseInsensitive); + + INT32 offset = regexp.indexIn(hexBody); +#endif + + while (offset >= 0) { + if (offset % 2 == 0) { + msg(UString("GUID pattern \"") + UString(guidPattern) + UString("\" found as \"") + hexBody.mid(offset, hexPattern.length()).toUpper() + UString("\" in ") + model->name(model->parent(index)) + UString("/") + model->name(index) + usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", offset / 2), index); } + +#if QT_VERSION_MAJOR >= 6 + offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset + 1, ®expmatch); +#else + offset = regexp.indexIn(hexBody, offset + 1); +#endif } - -#if QT_VERSION_MAJOR >= 6 - offset += 1; -#else - offset = regexp.indexIn(hexBody, offset + 1); -#endif - } - - return U_SUCCESS; -} - -USTATUS FfsFinder::findGuidPattern(const UModelIndex & index, const UByteArray & guidPattern, const UINT8 mode) -{ - if (guidPattern.isEmpty()) - return U_INVALID_PARAMETER; - - if (!index.isValid()) + return U_SUCCESS; - - bool hasChildren = (model->rowCount(index) > 0); - for (int i = 0; i < model->rowCount(index); i++) { - findGuidPattern(index.model()->index(i, index.column(), index), guidPattern, mode); } - - UByteArray data; - if (hasChildren) { - if (mode != SEARCH_MODE_BODY) - data = model->header(index); - } - else { - if (mode == SEARCH_MODE_HEADER) - data.append(model->header(index)); - else if (mode == SEARCH_MODE_BODY) - data.append(model->body(index)); - else - data.append(model->header(index)).append(model->body(index)); - } - - UString hexBody = UString(data.toHex()); - QList list = guidPattern.split('-'); - if (list.count() != 5) - return U_INVALID_PARAMETER; - - UByteArray hexPattern; - // Reverse first GUID block - hexPattern.append(list.at(0).mid(6, 2)); - hexPattern.append(list.at(0).mid(4, 2)); - hexPattern.append(list.at(0).mid(2, 2)); - hexPattern.append(list.at(0).mid(0, 2)); - // Reverse second GUID block - hexPattern.append(list.at(1).mid(2, 2)); - hexPattern.append(list.at(1).mid(0, 2)); - // Reverse third GUID block - hexPattern.append(list.at(2).mid(2, 2)); - hexPattern.append(list.at(2).mid(0, 2)); - // Append fourth and fifth GUID blocks as is - hexPattern.append(list.at(3)).append(list.at(4)); - - // Check for "all substrings" pattern - if (hexPattern.count('.') == hexPattern.length()) - return U_SUCCESS; - -#if QT_VERSION_MAJOR >= 6 - QRegularExpression regexp((QString)UString(hexPattern)); - regexp.setPatternOptions((QRegularExpression::PatternOptions)0x1); - QRegularExpressionMatch regexpmatch; - - INT32 offset = 0; - offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset, ®expmatch); -#else - QRegExp regexp(UString(hexPattern), Qt::CaseInsensitive); - - INT32 offset = regexp.indexIn(hexBody); -#endif - - while (offset >= 0) { - if (offset % 2 == 0) { - msg(UString("GUID pattern \"") + UString(guidPattern) - + UString("\" found as \"") + hexBody.mid(offset, hexPattern.length()).toUpper() - + UString("\" in ") + model->name(model->parent(index)) - + UString("/") + model->name(index) - + usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", offset / 2), - index); + + USTATUS FfsFinder::findTextPattern(const UModelIndex & index, const UString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive) + { + if (pattern.isEmpty()) + return U_INVALID_PARAMETER; + + if (!index.isValid()) + return U_SUCCESS; + + bool hasChildren = (model->rowCount(index) > 0); + for (int i = 0; i < model->rowCount(index); i++) { + findTextPattern(index.model()->index(i, index.column(), index), pattern, mode, unicode, caseSensitive); } - + + UByteArray body; + if (hasChildren) { + if (mode != SEARCH_MODE_BODY) + body = model->header(index); + } + else { + if (mode == SEARCH_MODE_HEADER) + body.append(model->header(index)); + else if (mode == SEARCH_MODE_BODY) + body.append(model->body(index)); + else + body.append(model->header(index)).append(model->body(index)); + } + + UString data; + if (unicode) #if QT_VERSION_MAJOR >= 6 - offset = (INT32)hexBody.indexOf(regexp, (qsizetype)offset + 1, ®expmatch); -#else - offset = regexp.indexIn(hexBody, offset + 1); -#endif - } - - return U_SUCCESS; -} - -USTATUS FfsFinder::findTextPattern(const UModelIndex & index, const UString & pattern, const UINT8 mode, const bool unicode, const Qt::CaseSensitivity caseSensitive) -{ - if (pattern.isEmpty()) - return U_INVALID_PARAMETER; - - if (!index.isValid()) - return U_SUCCESS; - - bool hasChildren = (model->rowCount(index) > 0); - for (int i = 0; i < model->rowCount(index); i++) { - findTextPattern(index.model()->index(i, index.column(), index), pattern, mode, unicode, caseSensitive); - } - - UByteArray body; - if (hasChildren) { - if (mode != SEARCH_MODE_BODY) - body = model->header(index); - } - else { - if (mode == SEARCH_MODE_HEADER) - body.append(model->header(index)); - else if (mode == SEARCH_MODE_BODY) - body.append(model->body(index)); - else - body.append(model->header(index)).append(model->body(index)); - } - - UString data; - if (unicode) -#if QT_VERSION_MAJOR >= 6 - data = UString::fromUtf16((const char16_t*)body.constData(), (int)(body.length() / 2)); + data = UString::fromUtf16((const char16_t*)body.constData(), (int)(body.length() / 2)); #else data = UString::fromUtf16((const ushort*)body.constData(), (int)(body.length() / 2)); #endif - else - data = UString::fromLatin1((const char*)body.constData(), body.length()); - - int offset = -1; - while ((offset = (int)data.indexOf(pattern, (int)(offset + 1), caseSensitive)) >= 0) { - - msg((unicode ? UString("Unicode") : UString("ASCII")) + UString(" text \"") + UString(pattern) - + UString("\" in ") + model->name(model->parent(index)) - + UString("/") + model->name(index) - + usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", (unicode ? offset * 2 : offset)), - index); + else + data = UString::fromLatin1((const char*)body.constData(), body.length()); + + int offset = -1; + while ((offset = (int)data.indexOf(pattern, (int)(offset + 1), caseSensitive)) >= 0) { + + msg((unicode ? UString("Unicode") : UString("ASCII")) + UString(" text \"") + UString(pattern) + + UString("\" in ") + model->name(model->parent(index)) + + UString("/") + model->name(index) + + usprintf(" at %s-offset %02Xh", mode == SEARCH_MODE_BODY ? "body" : "header", (unicode ? offset * 2 : offset)), + index); + } + + return U_SUCCESS; } - - return U_SUCCESS; -} diff --git a/UEFITool/guidlineedit.cpp b/UEFITool/guidlineedit.cpp index 2afe627..68818ac 100644 --- a/UEFITool/guidlineedit.cpp +++ b/UEFITool/guidlineedit.cpp @@ -1,25 +1,25 @@ /* guidlineedit.cpp - - Copyright (c) 2014, 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, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - */ + + Copyright (c) 2014, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "guidlineedit.h" GuidLineEdit::GuidLineEdit(QWidget * parent) - :QLineEdit(parent) +:QLineEdit(parent) { } GuidLineEdit::GuidLineEdit(const QString & contents, QWidget * parent) - :QLineEdit(contents, parent) +:QLineEdit(contents, parent) { } @@ -39,23 +39,24 @@ void GuidLineEdit::keyPressEvent(QKeyEvent * event) QString txt = text(); QString selected = selectedText(); - + if (!selected.isEmpty()) { pos = QLineEdit::selectionStart(); - for (int i = pos; i < pos + selected.count(); i++) + for (int i = pos; i < pos + selected.length(); i++) if (txt[i] != QChar('-')) txt[i] = QChar('.'); } - else + else { txt[pos] = QChar('.'); - + } + setCursorPosition(0); insert(txt); setCursorPosition(pos); - + return; } - + // Call original event handler QLineEdit::keyPressEvent(event); -} \ No newline at end of file +} diff --git a/UEFITool/hexspinbox.cpp b/UEFITool/hexspinbox.cpp index 587ce30..738a7cc 100644 --- a/UEFITool/hexspinbox.cpp +++ b/UEFITool/hexspinbox.cpp @@ -1,15 +1,15 @@ /* hexspinbox.cpp - - 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 - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - */ + + 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 + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "hexspinbox.h" #include diff --git a/UEFITool/hexviewdialog.cpp b/UEFITool/hexviewdialog.cpp index 227162a..49a0729 100644 --- a/UEFITool/hexviewdialog.cpp +++ b/UEFITool/hexviewdialog.cpp @@ -1,15 +1,15 @@ /* hexviewdialog.cpp - - 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 - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - */ + + 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 + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "hexviewdialog.h" diff --git a/UEFITool/searchdialog.cpp b/UEFITool/searchdialog.cpp index a0f74df..9b864fe 100644 --- a/UEFITool/searchdialog.cpp +++ b/UEFITool/searchdialog.cpp @@ -1,15 +1,15 @@ /* searchdialog.cpp - - Copyright (c) 2014, 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, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - */ + + Copyright (c) 2014, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "searchdialog.h" @@ -28,10 +28,10 @@ guidValidator(QRegExp("[0-9a-fA-F\\.]{8}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{4}-[0- ui->setupUi(this); ui->hexEdit->setValidator(&hexValidator); ui->guidEdit->setValidator(&guidValidator); - + // Connect connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(setEditFocus(int))); - + // Set initial focus setEditFocus(ui->tabWidget->currentIndex()); } diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index e93a5db..ab9a932 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -1,15 +1,15 @@ /* uefitool.cpp - - 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 - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - */ + + 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 + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "../version.h" #include "uefitool.h" @@ -22,7 +22,7 @@ version(tr(PROGRAM_VERSION)), markingEnabled(true) { clipboard = QApplication::clipboard(); - + // Create UI ui->setupUi(this); searchDialog = new SearchDialog(this); @@ -35,7 +35,7 @@ markingEnabled(true) ffsOps = NULL; ffsBuilder = NULL; ffsReport = NULL; - + // Connect signals to slots connect(ui->actionOpenImageFile, SIGNAL(triggered()), this, SLOT(openImageFile())); connect(ui->actionOpenImageFileInNewWindow, SIGNAL(triggered()), this, SLOT(openImageFileInNewWindow())); @@ -70,22 +70,22 @@ markingEnabled(true) connect(ui->actionGenerateReport, SIGNAL(triggered()), this, SLOT(generateReport())); connect(ui->actionToggleBootGuardMarking, SIGNAL(toggled(bool)), this, SLOT(toggleBootGuardMarking(bool))); connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(writeSettings())); - + // Enable Drag-and-Drop actions setAcceptDrops(true); - + // Disable Builder tab, doesn't work right now ui->messagesTabWidget->setTabEnabled(TAB_BUILDER, false); - + // Set current directory currentDir = "."; - + // Load built-in GUID database initGuidDatabase(":/guids.csv"); - + // Initialize non-persistent data init(); - + // Read stored settings readSettings(); } @@ -117,10 +117,10 @@ void UEFITool::init() ui->messagesTabWidget->setTabEnabled(TAB_SECURITY, false); ui->messagesTabWidget->setTabEnabled(TAB_SEARCH, false); ui->messagesTabWidget->setTabEnabled(TAB_BUILDER, false); - + // Set window title setWindowTitle(tr("UEFITool %1").arg(version)); - + // Disable menus ui->actionSearch->setEnabled(false); ui->actionGoToBase->setEnabled(false); @@ -135,7 +135,7 @@ void UEFITool::init() ui->menuStoreActions->setEnabled(false); ui->menuEntryActions->setEnabled(false); ui->menuMessageActions->setEnabled(false); - + // Create new model ... delete model; model = new TreeModel(); @@ -143,16 +143,16 @@ void UEFITool::init() // ... and ffsParser delete ffsParser; ffsParser = new FfsParser(model); - + // Set proper marking state model->setMarkingEnabled(markingEnabled); ui->actionToggleBootGuardMarking->setChecked(markingEnabled); - + // Connect connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, SLOT(populateUi(const QModelIndex &))); + this, SLOT(populateUi(const QModelIndex &))); connect(ui->structureTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - this, SLOT(populateUi(const QItemSelection &))); + this, SLOT(populateUi(const QItemSelection &))); connect(ui->parserMessagesListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*))); connect(ui->parserMessagesListWidget, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(enableMessagesCopyActions(QListWidgetItem*))); connect(ui->finderMessagesListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*))); @@ -161,7 +161,7 @@ void UEFITool::init() connect(ui->builderMessagesListWidget, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(enableMessagesCopyActions(QListWidgetItem*))); connect(ui->fitTableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(scrollTreeView(QTableWidgetItem*))); connect(ui->messagesTabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); - + // allow enter/return pressing to scroll tree view ui->parserMessagesListWidget->installEventFilter(this); ui->finderMessagesListWidget->installEventFilter(this); @@ -173,7 +173,7 @@ void UEFITool::populateUi(const QItemSelection &selected) if (selected.isEmpty()) { return; } - + populateUi(selected.indexes().at(0)); } @@ -183,13 +183,13 @@ void UEFITool::populateUi(const QModelIndex ¤t) if (!current.isValid()) { return; } - + UINT8 type = model->type(current); UINT8 subtype = model->subtype(current); - + // Set info text ui->infoEdit->setPlainText(model->info(current)); - + // Enable menus ui->menuCapsuleActions->setEnabled(type == Types::Capsule); ui->menuImageActions->setEnabled(type == Types::Image); @@ -199,47 +199,47 @@ void UEFITool::populateUi(const QModelIndex ¤t) ui->menuFileActions->setEnabled(type == Types::File); ui->menuSectionActions->setEnabled(type == Types::Section); ui->menuEntryActions->setEnabled(type == Types::Microcode - || type == Types::SlicData - || type == Types::NvarEntry - || type == Types::VssEntry - || type == Types::FsysEntry - || type == Types::EvsaEntry - || type == Types::FlashMapEntry - || type == Types::IfwiHeader - || type == Types::IfwiPartition - || type == Types::FptPartition - || type == Types::FptEntry - || type == Types::BpdtPartition - || type == Types::BpdtEntry - || type == Types::CpdPartition - || type == Types::CpdEntry - || type == Types::CpdExtension - || type == Types::CpdSpiEntry - ); + || type == Types::SlicData + || type == Types::NvarEntry + || type == Types::VssEntry + || type == Types::FsysEntry + || type == Types::EvsaEntry + || type == Types::FlashMapEntry + || type == Types::IfwiHeader + || type == Types::IfwiPartition + || type == Types::FptPartition + || type == Types::FptEntry + || type == Types::BpdtPartition + || type == Types::BpdtEntry + || type == Types::CpdPartition + || type == Types::CpdEntry + || type == Types::CpdExtension + || type == Types::CpdSpiEntry + ); ui->menuStoreActions->setEnabled(type == Types::VssStore - || type == Types::Vss2Store - || type == Types::FdcStore - || type == Types::FsysStore - || type == Types::EvsaStore - || type == Types::FtwStore - || type == Types::FlashMapStore - || type == Types::CmdbStore - || type == Types::FptStore - || type == Types::BpdtStore - || type == Types::CpdStore - ); - + || type == Types::Vss2Store + || type == Types::FdcStore + || type == Types::FsysStore + || type == Types::EvsaStore + || type == Types::FtwStore + || type == Types::FlashMapStore + || type == Types::CmdbStore + || type == Types::FptStore + || type == Types::BpdtStore + || type == Types::CpdStore + ); + // Enable actions ui->actionHexView->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current)); ui->actionBodyHexView->setDisabled(model->hasEmptyBody(current)); ui->actionUncompressedHexView->setDisabled(model->hasEmptyUncompressedData(current)); ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current)); ui->actionGoToData->setEnabled(type == Types::NvarEntry && subtype == Subtypes::LinkNvarEntry); - + // Disable rebuild for now //ui->actionRebuild->setDisabled(type == Types::Region && subtype == Subtypes::DescriptorRegion); //ui->actionReplace->setDisabled(type == Types::Region && subtype == Subtypes::DescriptorRegion); - + //ui->actionRebuild->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section); ui->actionExtractBody->setDisabled(model->hasEmptyBody(current)); ui->actionExtractBodyUncompressed->setDisabled(model->hasEmptyUncompressedData(current)); @@ -251,7 +251,7 @@ void UEFITool::populateUi(const QModelIndex ¤t) //ui->actionInsertAfter->setEnabled(type == Types::File || type == Types::Section); //ui->actionReplace->setEnabled((type == Types::Region && subtype != Subtypes::DescriptorRegion) || type == Types::Volume || type == Types::File || type == Types::Section); //ui->actionReplaceBody->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section); - + ui->menuMessageActions->setEnabled(false); } @@ -259,9 +259,9 @@ void UEFITool::search() { if (searchDialog->exec() != QDialog::Accepted) return; - + QModelIndex rootIndex = model->index(0, 0); - + int index = searchDialog->ui->tabWidget->currentIndex(); if (index == 0) { // Hex pattern searchDialog->ui->hexEdit->setFocus(); @@ -307,7 +307,7 @@ void UEFITool::search() else mode = SEARCH_MODE_ALL; ffsFinder->findTextPattern(rootIndex, pattern, mode, searchDialog->ui->textUnicodeCheckBox->isChecked(), - (Qt::CaseSensitivity) searchDialog->ui->textCaseSensitiveCheckBox->isChecked()); + (Qt::CaseSensitivity) searchDialog->ui->textCaseSensitiveCheckBox->isChecked()); showFinderMessages(); } } @@ -317,7 +317,7 @@ void UEFITool::hexView() QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex(); if (!index.isValid()) return; - + hexViewDialog->setItem(index, HexViewDialog::HexViewType::fullHexView); hexViewDialog->exec(); } @@ -327,7 +327,7 @@ void UEFITool::bodyHexView() QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex(); if (!index.isValid()) return; - + hexViewDialog->setItem(index, HexViewDialog::HexViewType::bodyHexView); hexViewDialog->exec(); } @@ -337,7 +337,7 @@ void UEFITool::uncompressedHexView() QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex(); if (!index.isValid()) return; - + hexViewDialog->setItem(index, HexViewDialog::HexViewType::uncompressedHexView); hexViewDialog->exec(); } @@ -348,7 +348,7 @@ void UEFITool::goToBase() goToBaseDialog->ui->hexSpinBox->selectAll(); if (goToBaseDialog->exec() != QDialog::Accepted) return; - + UINT32 offset = (UINT32)goToBaseDialog->ui->hexSpinBox->value(); QModelIndex index = model->findByBase(offset); if (index.isValid()) { @@ -363,7 +363,7 @@ void UEFITool::goToAddress() goToAddressDialog->ui->hexSpinBox->selectAll(); if (goToAddressDialog->exec() != QDialog::Accepted) return; - + UINT32 address = (UINT32)goToAddressDialog->ui->hexSpinBox->value(); QModelIndex index = model->findByBase(address - (UINT32)ffsParser->getAddressDiff()); if (index.isValid()) { @@ -377,14 +377,14 @@ void UEFITool::goToData() QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex(); if (!index.isValid() || model->type(index) != Types::NvarEntry || model->subtype(index) != Subtypes::LinkNvarEntry) return; - + // Get parent QModelIndex parent = model->parent(index); - + for (int i = index.row(); i < model->rowCount(parent); i++) { if (model->hasEmptyParsingData(index)) continue; - + UByteArray rdata = model->parsingData(index); const NVAR_ENTRY_PARSING_DATA* pdata = (const NVAR_ENTRY_PARSING_DATA*)rdata.constData(); UINT32 lastVariableFlag = pdata->emptyByte ? 0xFFFFFF : 0; @@ -393,13 +393,13 @@ void UEFITool::goToData() ui->structureTreeView->scrollTo(index, QAbstractItemView::PositionAtCenter); ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows | QItemSelectionModel::Clear); } - + for (int j = i + 1; j < model->rowCount(parent); j++) { QModelIndex currentIndex = parent.model()->index(j, 0, parent); - + if (model->hasEmptyParsingData(currentIndex)) continue; - + if (model->offset(currentIndex) == offset + pdata->next) { index = currentIndex; break; @@ -441,7 +441,7 @@ void UEFITool::replaceBody() void UEFITool::replace(const UINT8 mode) { U_UNUSED_PARAMETER(mode); - + } void UEFITool::extractAsIs() @@ -464,7 +464,7 @@ void UEFITool::extract(const UINT8 mode) QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex(); if (!index.isValid()) return; - + QByteArray extracted; QString name; USTATUS result = ffsOps->extract(index, name, extracted, mode); @@ -472,89 +472,89 @@ void UEFITool::extract(const UINT8 mode) QMessageBox::critical(this, tr("Extraction failed"), errorCodeToUString(result), QMessageBox::Ok); return; } - + name = QDir::toNativeSeparators(currentDir + QDir::separator() + name); - + //ui->statusBar->showMessage(name); - + UINT8 type = model->type(index); UINT8 subtype = model->subtype(index); QString path; if (mode == EXTRACT_MODE_AS_IS) { switch (type) { - case Types::Capsule: path = QFileDialog::getSaveFileName(this, tr("Save capsule to file"), name + ".cap", tr("Capsule files (*.cap *.bin);;All files (*)")); break; - case Types::Image: path = QFileDialog::getSaveFileName(this, tr("Save image to file"), name + ".rom", tr("Image files (*.rom *.bin);;All files (*)")); break; - case Types::Region: path = QFileDialog::getSaveFileName(this, tr("Save region to file"), name + ".rgn", tr("Region files (*.rgn *.bin);;All files (*)")); break; - case Types::Padding: path = QFileDialog::getSaveFileName(this, tr("Save padding to file"), name + ".pad", tr("Padding files (*.pad *.bin);;All files (*)")); break; - case Types::Volume: path = QFileDialog::getSaveFileName(this, tr("Save volume to file"), name + ".vol", tr("Volume files (*.vol *.bin);;All files (*)")); break; - case Types::File: path = QFileDialog::getSaveFileName(this, tr("Save FFS file to file"), name + ".ffs", tr("FFS files (*.ffs *.bin);;All files (*)")); break; - case Types::Section: path = QFileDialog::getSaveFileName(this, tr("Save section to file"), name + ".sct", tr("Section files (*.sct *.bin);;All files (*)")); break; - case Types::NvarEntry: path = QFileDialog::getSaveFileName(this, tr("Save NVAR entry to file"), name + ".nvar", tr("NVAR entry files (*.nvar *.bin);;All files (*)")); break; - case Types::VssEntry: path = QFileDialog::getSaveFileName(this, tr("Save VSS entry to file"), name + ".vss", tr("VSS entry files (*.vss *.bin);;All files (*)")); break; - case Types::FsysEntry: path = QFileDialog::getSaveFileName(this, tr("Save Fsys entry to file"), name + ".fse", tr("Fsys entry files (*.fse *.bin);;All files (*)")); break; - case Types::EvsaEntry: path = QFileDialog::getSaveFileName(this, tr("Save EVSA entry to file"), name + ".evse", tr("EVSA entry files (*.evse *.bin);;All files (*)")); break; - case Types::FlashMapEntry: path = QFileDialog::getSaveFileName(this, tr("Save FlashMap entry to file"), name + ".fme", tr("FlashMap entry files (*.fme *.bin);;All files (*)")); break; - case Types::VssStore: path = QFileDialog::getSaveFileName(this, tr("Save VSS store to file"), name + ".vss", tr("VSS store files (*.vss *.bin);;All files (*)")); break; - case Types::Vss2Store: path = QFileDialog::getSaveFileName(this, tr("Save VSS2 store to file"), name + ".vss2", tr("VSS2 store files (*.vss2 *.bin);;All files (*)")); break; - case Types::FdcStore: path = QFileDialog::getSaveFileName(this, tr("Save FDC store to file"), name + ".fdc", tr("FDC store files (*.fdc *.bin);;All files (*)")); break; - case Types::FsysStore: path = QFileDialog::getSaveFileName(this, tr("Save Fsys store to file"), name + ".fsys", tr("Fsys store files (*.fsys *.bin);;All files (*)")); break; - case Types::EvsaStore: path = QFileDialog::getSaveFileName(this, tr("Save EVSA store to file"), name + ".evsa", tr("EVSA store files (*.evsa *.bin);;All files (*)")); break; - case Types::FtwStore: path = QFileDialog::getSaveFileName(this, tr("Save FTW store to file"), name + ".ftw", tr("FTW store files (*.ftw *.bin);;All files (*)")); break; - case Types::FlashMapStore: path = QFileDialog::getSaveFileName(this, tr("Save FlashMap store to file"), name + ".fmap", tr("FlashMap store files (*.fmap *.bin);;All files (*)")); break; - case Types::CmdbStore: path = QFileDialog::getSaveFileName(this, tr("Save CMDB store to file"), name + ".cmdb", tr("CMDB store files (*.cmdb *.bin);;All files (*)")); break; - case Types::Microcode: path = QFileDialog::getSaveFileName(this, tr("Save microcode binary to file"), name + ".ucd", tr("Microcode binary files (*.ucd *.bin);;All files (*)")); break; - case Types::SlicData: - if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey to file"), name + ".spk", tr("SLIC pubkey files (*.spk *.bin);;All files (*)")); - else path = QFileDialog::getSaveFileName(this, tr("Save SLIC marker to file"), name + ".smk", tr("SLIC marker files (*.smk *.bin);;All files (*)")); - break; - default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); + case Types::Capsule: path = QFileDialog::getSaveFileName(this, tr("Save capsule to file"), name + ".cap", tr("Capsule files (*.cap *.bin);;All files (*)")); break; + case Types::Image: path = QFileDialog::getSaveFileName(this, tr("Save image to file"), name + ".rom", tr("Image files (*.rom *.bin);;All files (*)")); break; + case Types::Region: path = QFileDialog::getSaveFileName(this, tr("Save region to file"), name + ".rgn", tr("Region files (*.rgn *.bin);;All files (*)")); break; + case Types::Padding: path = QFileDialog::getSaveFileName(this, tr("Save padding to file"), name + ".pad", tr("Padding files (*.pad *.bin);;All files (*)")); break; + case Types::Volume: path = QFileDialog::getSaveFileName(this, tr("Save volume to file"), name + ".vol", tr("Volume files (*.vol *.bin);;All files (*)")); break; + case Types::File: path = QFileDialog::getSaveFileName(this, tr("Save FFS file to file"), name + ".ffs", tr("FFS files (*.ffs *.bin);;All files (*)")); break; + case Types::Section: path = QFileDialog::getSaveFileName(this, tr("Save section to file"), name + ".sct", tr("Section files (*.sct *.bin);;All files (*)")); break; + case Types::NvarEntry: path = QFileDialog::getSaveFileName(this, tr("Save NVAR entry to file"), name + ".nvar", tr("NVAR entry files (*.nvar *.bin);;All files (*)")); break; + case Types::VssEntry: path = QFileDialog::getSaveFileName(this, tr("Save VSS entry to file"), name + ".vss", tr("VSS entry files (*.vss *.bin);;All files (*)")); break; + case Types::FsysEntry: path = QFileDialog::getSaveFileName(this, tr("Save Fsys entry to file"), name + ".fse", tr("Fsys entry files (*.fse *.bin);;All files (*)")); break; + case Types::EvsaEntry: path = QFileDialog::getSaveFileName(this, tr("Save EVSA entry to file"), name + ".evse", tr("EVSA entry files (*.evse *.bin);;All files (*)")); break; + case Types::FlashMapEntry: path = QFileDialog::getSaveFileName(this, tr("Save FlashMap entry to file"), name + ".fme", tr("FlashMap entry files (*.fme *.bin);;All files (*)")); break; + case Types::VssStore: path = QFileDialog::getSaveFileName(this, tr("Save VSS store to file"), name + ".vss", tr("VSS store files (*.vss *.bin);;All files (*)")); break; + case Types::Vss2Store: path = QFileDialog::getSaveFileName(this, tr("Save VSS2 store to file"), name + ".vss2", tr("VSS2 store files (*.vss2 *.bin);;All files (*)")); break; + case Types::FdcStore: path = QFileDialog::getSaveFileName(this, tr("Save FDC store to file"), name + ".fdc", tr("FDC store files (*.fdc *.bin);;All files (*)")); break; + case Types::FsysStore: path = QFileDialog::getSaveFileName(this, tr("Save Fsys store to file"), name + ".fsys", tr("Fsys store files (*.fsys *.bin);;All files (*)")); break; + case Types::EvsaStore: path = QFileDialog::getSaveFileName(this, tr("Save EVSA store to file"), name + ".evsa", tr("EVSA store files (*.evsa *.bin);;All files (*)")); break; + case Types::FtwStore: path = QFileDialog::getSaveFileName(this, tr("Save FTW store to file"), name + ".ftw", tr("FTW store files (*.ftw *.bin);;All files (*)")); break; + case Types::FlashMapStore: path = QFileDialog::getSaveFileName(this, tr("Save FlashMap store to file"), name + ".fmap", tr("FlashMap store files (*.fmap *.bin);;All files (*)")); break; + case Types::CmdbStore: path = QFileDialog::getSaveFileName(this, tr("Save CMDB store to file"), name + ".cmdb", tr("CMDB store files (*.cmdb *.bin);;All files (*)")); break; + case Types::Microcode: path = QFileDialog::getSaveFileName(this, tr("Save microcode binary to file"), name + ".ucd", tr("Microcode binary files (*.ucd *.bin);;All files (*)")); break; + case Types::SlicData: + if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey to file"), name + ".spk", tr("SLIC pubkey files (*.spk *.bin);;All files (*)")); + else path = QFileDialog::getSaveFileName(this, tr("Save SLIC marker to file"), name + ".smk", tr("SLIC marker files (*.smk *.bin);;All files (*)")); + break; + default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); } } else if (mode == EXTRACT_MODE_BODY || mode == EXTRACT_MODE_BODY_UNCOMPRESSED) { switch (type) { - case Types::Capsule: path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), name + ".rom", tr("Image files (*.rom *.bin);;All files (*)")); break; - case Types::Volume: path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), name + ".vbd", tr("Volume body files (*.vbd *.bin);;All files (*)")); break; - case Types::File: - if (subtype == EFI_FV_FILETYPE_ALL - || subtype == EFI_FV_FILETYPE_RAW) path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to raw file"), name + ".raw", tr("Raw files (*.raw *.bin);;All files (*)")); - else path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to file"), name + ".fbd", tr("FFS file body files (*.fbd *.bin);;All files (*)")); - break; - case Types::Section: - if (subtype == EFI_SECTION_COMPRESSION - || subtype == EFI_SECTION_GUID_DEFINED - || subtype == EFI_SECTION_DISPOSABLE) path = QFileDialog::getSaveFileName(this, tr("Save encapsulation section body to FFS body file"), name + ".fbd", tr("FFS file body files (*.fbd *.bin);;All files (*)")); - else if (subtype == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) path = QFileDialog::getSaveFileName(this, tr("Save section body to volume file"), name + ".vol", tr("Volume files (*.vol *.bin);;All files (*)")); - else if (subtype == EFI_SECTION_RAW) path = QFileDialog::getSaveFileName(this, tr("Save section body to raw file"), name + ".raw", tr("Raw files (*.raw *.bin);;All files (*)")); - else if (subtype == EFI_SECTION_PE32 - || subtype == EFI_SECTION_TE - || subtype == EFI_SECTION_PIC) path = QFileDialog::getSaveFileName(this, tr("Save section body to EFI executable file"), name + ".efi", tr("EFI executable files (*.efi *.bin);;All files (*)")); - else path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); - break; - case Types::NvarEntry: - case Types::VssEntry: - case Types::EvsaEntry: - case Types::FlashMapEntry: - case Types::FsysEntry: path = QFileDialog::getSaveFileName(this, tr("Save entry body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); break; - case Types::VssStore: - case Types::Vss2Store: - case Types::FtwStore: - case Types::FdcStore: - case Types::FsysStore: - case Types::FlashMapStore: - case Types::CmdbStore: path = QFileDialog::getSaveFileName(this, tr("Save store body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); break; - case Types::Microcode: path = QFileDialog::getSaveFileName(this, tr("Save microcode body to file"), name + ".ucb", tr("Microcode body files (*.ucb *.bin);;All files (*)")); break; - case Types::SlicData: - if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey body to file"), name + ".spb", tr("SLIC pubkey body files (*.spb *.bin);;All files (*)")); - else path = QFileDialog::getSaveFileName(this, tr("Save SLIC marker body to file"), name + ".smb", tr("SLIC marker body files (*.smb *.bin);;All files (*)")); - break; - default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); + case Types::Capsule: path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), name + ".rom", tr("Image files (*.rom *.bin);;All files (*)")); break; + case Types::Volume: path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), name + ".vbd", tr("Volume body files (*.vbd *.bin);;All files (*)")); break; + case Types::File: + if (subtype == EFI_FV_FILETYPE_ALL + || subtype == EFI_FV_FILETYPE_RAW) path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to raw file"), name + ".raw", tr("Raw files (*.raw *.bin);;All files (*)")); + else path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to file"), name + ".fbd", tr("FFS file body files (*.fbd *.bin);;All files (*)")); + break; + case Types::Section: + if (subtype == EFI_SECTION_COMPRESSION + || subtype == EFI_SECTION_GUID_DEFINED + || subtype == EFI_SECTION_DISPOSABLE) path = QFileDialog::getSaveFileName(this, tr("Save encapsulation section body to FFS body file"), name + ".fbd", tr("FFS file body files (*.fbd *.bin);;All files (*)")); + else if (subtype == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) path = QFileDialog::getSaveFileName(this, tr("Save section body to volume file"), name + ".vol", tr("Volume files (*.vol *.bin);;All files (*)")); + else if (subtype == EFI_SECTION_RAW) path = QFileDialog::getSaveFileName(this, tr("Save section body to raw file"), name + ".raw", tr("Raw files (*.raw *.bin);;All files (*)")); + else if (subtype == EFI_SECTION_PE32 + || subtype == EFI_SECTION_TE + || subtype == EFI_SECTION_PIC) path = QFileDialog::getSaveFileName(this, tr("Save section body to EFI executable file"), name + ".efi", tr("EFI executable files (*.efi *.bin);;All files (*)")); + else path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); + break; + case Types::NvarEntry: + case Types::VssEntry: + case Types::EvsaEntry: + case Types::FlashMapEntry: + case Types::FsysEntry: path = QFileDialog::getSaveFileName(this, tr("Save entry body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); break; + case Types::VssStore: + case Types::Vss2Store: + case Types::FtwStore: + case Types::FdcStore: + case Types::FsysStore: + case Types::FlashMapStore: + case Types::CmdbStore: path = QFileDialog::getSaveFileName(this, tr("Save store body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); break; + case Types::Microcode: path = QFileDialog::getSaveFileName(this, tr("Save microcode body to file"), name + ".ucb", tr("Microcode body files (*.ucb *.bin);;All files (*)")); break; + case Types::SlicData: + if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey body to file"), name + ".spb", tr("SLIC pubkey body files (*.spb *.bin);;All files (*)")); + else path = QFileDialog::getSaveFileName(this, tr("Save SLIC marker body to file"), name + ".smb", tr("SLIC marker body files (*.smb *.bin);;All files (*)")); + break; + default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); } } else path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); - + if (path.trimmed().isEmpty()) return; - + QFile outputFile; outputFile.setFileName(path); if (!outputFile.open(QFile::WriteOnly)) { @@ -568,27 +568,27 @@ void UEFITool::extract(const UINT8 mode) void UEFITool::rebuild() { - + } void UEFITool::remove() { - + } void UEFITool::about() { QMessageBox::about(this, tr("About UEFITool"), tr( - "Copyright (c) 2019, Nikolaj Schlej.
" - "Program icon made by Alexander Zhidkov.
" - "The program uses QHexEdit2 library made by Simsys.
" - "Qt-less engine is using Bstrlib made by Paul Hsieh.

" - "The program is dedicated to RevoGirl. Rest in peace, young genius.

" - "The program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License.
" - "The full text of the license may be found at OpenSource.org.

" - "THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN \"AS IS\" BASIS, " - "WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, " - "EITHER EXPRESS OR IMPLIED.")); + "Copyright (c) 2019, Nikolaj Schlej.
" + "Program icon made by Alexander Zhidkov.
" + "The program uses QHexEdit2 library made by Simsys.
" + "Qt-less engine is using Bstrlib made by Paul Hsieh.

" + "The program is dedicated to RevoGirl. Rest in peace, young genius.

" + "The program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License.
" + "The full text of the license may be found at OpenSource.org.

" + "THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN \"AS IS\" BASIS, " + "WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, " + "EITHER EXPRESS OR IMPLIED.")); } void UEFITool::aboutQt() @@ -603,7 +603,7 @@ void UEFITool::exit() void UEFITool::saveImageFile() { - + } void UEFITool::openImageFile() @@ -624,31 +624,31 @@ void UEFITool::openImageFile(QString path) { if (path.trimmed().isEmpty()) return; - + QFileInfo fileInfo = QFileInfo(path); - + if (!fileInfo.exists()) { ui->statusBar->showMessage(tr("Please select existing file")); return; } - + QFile inputFile; inputFile.setFileName(path); - + if (!inputFile.open(QFile::ReadOnly)) { QMessageBox::critical(this, tr("Image parsing failed"), tr("Can't open input file for reading"), QMessageBox::Ok); return; } - + QByteArray buffer = inputFile.readAll(); inputFile.close(); - + init(); setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName())); - + // Parse the image USTATUS result = ffsParser->parse(buffer); - + showParserMessages(); if (result) { QMessageBox::critical(this, tr("Image parsing failed"), errorCodeToUString(result), QMessageBox::Ok); @@ -656,15 +656,15 @@ void UEFITool::openImageFile(QString path) } else ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName())); - + ffsParser->outputInfo(); - + // Enable or disable FIT tab showFitTable(); - + // Enable or disable Security tab showSecurityInfo(); - + // Enable search ... delete ffsFinder; ffsFinder = new FfsFinder(model); @@ -675,21 +675,21 @@ void UEFITool::openImageFile(QString path) // ... and reports delete ffsReport; ffsReport = new FfsReport(model); - + // Enable goToBase and goToAddress ui->actionGoToBase->setEnabled(true); if (ffsParser->getAddressDiff() <= 0xFFFFFFFFUL) ui->actionGoToAddress->setEnabled(true); - + // Enable generateReport ui->actionGenerateReport->setEnabled(true); - + // Enable saving GUIDs ui->actionExportDiscoveredGuids->setEnabled(true); - + // Set current directory currentDir = fileInfo.absolutePath(); - + // Set current path currentPath = path; } @@ -748,7 +748,7 @@ void UEFITool::clearMessages() if (ffsBuilder) ffsBuilder->clearMessages(); ui->builderMessagesListWidget->clear(); } - + ui->menuMessageActions->setEnabled(false); ui->actionMessagesCopy->setEnabled(false); ui->actionMessagesCopyAll->setEnabled(false); @@ -766,15 +766,15 @@ bool UEFITool::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent* key = static_cast(event); - + if (key->key() == Qt::Key_Enter || key->key() == Qt::Key_Return) { QListWidget* list = qobject_cast(obj); - + if (list != NULL && list->currentItem() != NULL) emit list->itemDoubleClicked(list->currentItem()); } } - + return QObject::eventFilter(obj, event); } @@ -795,315 +795,315 @@ void UEFITool::showParserMessages() ui->parserMessagesListWidget->clear(); if (!ffsParser) return; - + std::vector > messages = ffsParser->getMessages(); - + #if QT_VERSION_MAJOR < 6 std::pair msg; - + foreach (msg, messages) { #else - for (const auto &msg : messages) { + for (const auto &msg : messages) { #endif - QListWidgetItem* item = new QListWidgetItem(msg.first, NULL, 0); - item->setData(Qt::UserRole, QByteArray((const char*)&msg.second, sizeof(msg.second))); - ui->parserMessagesListWidget->addItem(item); + QListWidgetItem* item = new QListWidgetItem(msg.first, NULL, 0); + item->setData(Qt::UserRole, QByteArray((const char*)&msg.second, sizeof(msg.second))); + ui->parserMessagesListWidget->addItem(item); + } + + ui->messagesTabWidget->setCurrentIndex(TAB_PARSER); + ui->parserMessagesListWidget->scrollToBottom(); } - - ui->messagesTabWidget->setCurrentIndex(TAB_PARSER); - ui->parserMessagesListWidget->scrollToBottom(); -} - -void UEFITool::showFinderMessages() -{ - ui->finderMessagesListWidget->clear(); - if (!ffsParser) - return; - - std::vector > messages = ffsFinder->getMessages(); - -#if QT_VERSION_MAJOR < 6 - std::pair msg; - - foreach (msg, messages) { -#else - for (const auto &msg : messages) { -#endif - QListWidgetItem* item = new QListWidgetItem(msg.first, NULL, 0); - item->setData(Qt::UserRole, QByteArray((const char*)&msg.second, sizeof(msg.second)));; - ui->finderMessagesListWidget->addItem(item); - } - - ui->messagesTabWidget->setTabEnabled(TAB_SEARCH, true); - ui->messagesTabWidget->setCurrentIndex(TAB_SEARCH); - ui->finderMessagesListWidget->scrollToBottom(); -} - -void UEFITool::showBuilderMessages() -{ - ui->builderMessagesListWidget->clear(); - if (!ffsBuilder) - return; - - std::vector > messages = ffsBuilder->getMessages(); - -#if QT_VERSION_MAJOR < 6 - std::pair msg; - - foreach (msg, messages) { -#else - for (const auto &msg : messages) { -#endif - QListWidgetItem* item = new QListWidgetItem(msg.first, NULL, 0); - item->setData(Qt::UserRole, QByteArray((const char*)&msg.second, sizeof(msg.second))); - ui->builderMessagesListWidget->addItem(item); - } - - ui->messagesTabWidget->setTabEnabled(TAB_BUILDER, true); - ui->messagesTabWidget->setCurrentIndex(TAB_BUILDER); - ui->builderMessagesListWidget->scrollToBottom(); -} - -void UEFITool::scrollTreeView(QListWidgetItem* item) -{ - QByteArray second = item->data(Qt::UserRole).toByteArray(); - QModelIndex *index = (QModelIndex *)second.data(); - if (index && index->isValid()) { - ui->structureTreeView->scrollTo(*index, QAbstractItemView::PositionAtCenter); - ui->structureTreeView->selectionModel()->select(*index, QItemSelectionModel::Select | QItemSelectionModel::Rows | QItemSelectionModel::Clear); - } -} - -void UEFITool::scrollTreeView(QTableWidgetItem* item) -{ - QByteArray second = item->data(Qt::UserRole).toByteArray(); - QModelIndex *index = (QModelIndex *)second.data(); - if (index && index->isValid()) { - ui->structureTreeView->scrollTo(*index, QAbstractItemView::PositionAtCenter); - ui->structureTreeView->selectionModel()->select(*index, QItemSelectionModel::Select | QItemSelectionModel::Rows | QItemSelectionModel::Clear); - } -} - -void UEFITool::contextMenuEvent(QContextMenuEvent* event) -{ - // The checks involving underMouse do not work well enough on macOS, and result in right-click sometimes - // not showing any context menu at all. Most likely it is a bug in Qt, which does not affect other systems. - // For this reason we reimplement this manually. - if (ui->parserMessagesListWidget->rect().contains(ui->parserMessagesListWidget->mapFromGlobal(event->globalPos())) || - ui->finderMessagesListWidget->rect().contains(ui->finderMessagesListWidget->mapFromGlobal(event->globalPos())) || - ui->builderMessagesListWidget->rect().contains(ui->builderMessagesListWidget->mapFromGlobal(event->globalPos()))) { - ui->menuMessageActions->exec(event->globalPos()); - return; - } - - - if (!ui->structureTreeView->rect().contains(ui->structureTreeView->mapFromGlobal(event->globalPos()))) - return; - - QPoint pt = event->pos(); - QModelIndex index = ui->structureTreeView->indexAt(ui->structureTreeView->viewport()->mapFrom(this, pt)); - if (!index.isValid()) { - return; - } - - switch (model->type(index)) + + void UEFITool::showFinderMessages() { - case Types::Capsule: ui->menuCapsuleActions->exec(event->globalPos()); break; - case Types::Image: ui->menuImageActions->exec(event->globalPos()); break; - case Types::Region: ui->menuRegionActions->exec(event->globalPos()); break; - case Types::Padding: ui->menuPaddingActions->exec(event->globalPos()); break; - case Types::Volume: ui->menuVolumeActions->exec(event->globalPos()); break; - case Types::File: ui->menuFileActions->exec(event->globalPos()); break; - case Types::Section: ui->menuSectionActions->exec(event->globalPos()); break; - case Types::VssStore: - case Types::Vss2Store: - case Types::FdcStore: - case Types::FsysStore: - case Types::EvsaStore: - case Types::FtwStore: - case Types::FlashMapStore: - case Types::CmdbStore: - case Types::FptStore: - case Types::CpdStore: - case Types::BpdtStore: ui->menuStoreActions->exec(event->globalPos()); break; - case Types::FreeSpace: break; // No menu needed for FreeSpace item - default: ui->menuEntryActions->exec(event->globalPos()); break; - } -} - -void UEFITool::readSettings() -{ - QSettings settings(this); - restoreGeometry(settings.value("mainWindow/geometry").toByteArray()); - restoreState(settings.value("mainWindow/windowState").toByteArray()); - QList horList, vertList; - horList.append(settings.value("mainWindow/treeWidth", 600).toInt()); - horList.append(settings.value("mainWindow/infoWidth", 180).toInt()); - vertList.append(settings.value("mainWindow/treeHeight", 400).toInt()); - vertList.append(settings.value("mainWindow/messageHeight", 180).toInt()); - ui->infoSplitter->setSizes(horList); - ui->messagesSplitter->setSizes(vertList); - ui->structureTreeView->setColumnWidth(0, settings.value("tree/columnWidth0", ui->structureTreeView->columnWidth(0)).toInt()); - ui->structureTreeView->setColumnWidth(1, settings.value("tree/columnWidth1", ui->structureTreeView->columnWidth(1)).toInt()); - ui->structureTreeView->setColumnWidth(2, settings.value("tree/columnWidth2", ui->structureTreeView->columnWidth(2)).toInt()); - ui->structureTreeView->setColumnWidth(3, settings.value("tree/columnWidth3", ui->structureTreeView->columnWidth(3)).toInt()); - markingEnabled = settings.value("tree/markingEnabled", true).toBool(); - ui->actionToggleBootGuardMarking->setChecked(markingEnabled); - - // Set monospace font for some controls - QString fontName; - int fontSize; -#if defined Q_OS_OSX - fontName = settings.value("mainWindow/fontName", QString("Menlo")).toString(); - fontSize = settings.value("mainWindow/fontSize", 10).toInt(); -#elif defined Q_OS_WIN - fontName = settings.value("mainWindow/fontName", QString("Consolas")).toString(); - fontSize = settings.value("mainWindow/fontSize", 9).toInt(); + ui->finderMessagesListWidget->clear(); + if (!ffsParser) + return; + + std::vector > messages = ffsFinder->getMessages(); + +#if QT_VERSION_MAJOR < 6 + std::pair msg; + + foreach (msg, messages) { #else - fontName = settings.value("mainWindow/fontName", QString("Courier New")).toString(); - fontSize = settings.value("mainWindow/fontSize", 10).toInt(); + for (const auto &msg : messages) { #endif - currentFont = QFont(fontName, fontSize); - ui->infoEdit->setFont(currentFont); - ui->parserMessagesListWidget->setFont(currentFont); - ui->finderMessagesListWidget->setFont(currentFont); - ui->builderMessagesListWidget->setFont(currentFont); - ui->fitTableWidget->setFont(currentFont); - ui->securityEdit->setFont(currentFont); - ui->structureTreeView->setFont(currentFont); - searchDialog->ui->guidEdit->setFont(currentFont); - searchDialog->ui->hexEdit->setFont(currentFont); - hexViewDialog->setFont(currentFont); - goToAddressDialog->ui->hexSpinBox->setFont(currentFont); - goToBaseDialog->ui->hexSpinBox->setFont(currentFont); -} - -void UEFITool::writeSettings() -{ - QSettings settings(this); - settings.setValue("mainWindow/geometry", saveGeometry()); - settings.setValue("mainWindow/windowState", saveState()); - settings.setValue("mainWindow/treeWidth", ui->structureGroupBox->width()); - settings.setValue("mainWindow/infoWidth", ui->infoGroupBox->width()); - settings.setValue("mainWindow/treeHeight", ui->structureGroupBox->height()); - settings.setValue("mainWindow/messageHeight", ui->messagesTabWidget->height()); - settings.setValue("tree/columnWidth0", ui->structureTreeView->columnWidth(0)); - settings.setValue("tree/columnWidth1", ui->structureTreeView->columnWidth(1)); - settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2)); - settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3)); - settings.setValue("tree/markingEnabled", markingEnabled); - settings.setValue("mainWindow/fontName", currentFont.family()); - settings.setValue("mainWindow/fontSize", currentFont.pointSize()); -} - -void UEFITool::showFitTable() -{ - std::vector, UModelIndex> > fitTable = ffsParser->getFitTable(); - if (fitTable.empty()) { - // Disable FIT tab - ui->messagesTabWidget->setTabEnabled(TAB_FIT, false); - return; - } - - // Enable FIT tab - ui->messagesTabWidget->setTabEnabled(TAB_FIT, true); - - // Set up the FIT table - ui->fitTableWidget->clear(); - ui->fitTableWidget->setRowCount((int)fitTable.size()); - ui->fitTableWidget->setColumnCount(6); - ui->fitTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Address") << tr("Size") << tr("Version") << tr("Checksum") << tr("Type") << tr("Information")); - ui->fitTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->fitTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->fitTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); - ui->fitTableWidget->horizontalHeader()->setStretchLastSection(true); - - // Add all data to the table widget - for (size_t i = 0; i < fitTable.size(); i++) { - for (UINT8 j = 0; j < 6; j++) { - QTableWidgetItem* item = new QTableWidgetItem(fitTable[i].first[j]); - item->setData(Qt::UserRole, QByteArray((const char*)&fitTable[i].second, sizeof(fitTable[i].second))); - ui->fitTableWidget->setItem((int)i, j, item); - } - } - - ui->fitTableWidget->resizeColumnsToContents(); - ui->fitTableWidget->resizeRowsToContents(); - ui->messagesTabWidget->setCurrentIndex(TAB_FIT); -} - -void UEFITool::showSecurityInfo() -{ - // Get security info - UString secInfo = ffsParser->getSecurityInfo(); - if (secInfo.isEmpty()) { - ui->messagesTabWidget->setTabEnabled(TAB_SECURITY, false); - return; - } - - ui->messagesTabWidget->setTabEnabled(TAB_SECURITY, true); - ui->securityEdit->setPlainText(secInfo); - ui->messagesTabWidget->setCurrentIndex(TAB_SECURITY); -} - -void UEFITool::currentTabChanged(int index) -{ - U_UNUSED_PARAMETER(index); - - ui->menuMessageActions->setEnabled(false); - ui->actionMessagesCopy->setEnabled(false); - ui->actionMessagesCopyAll->setEnabled(false); - ui->actionMessagesClear->setEnabled(false); -} - -void UEFITool::loadGuidDatabase() -{ - QString path = QFileDialog::getOpenFileName(this, tr("Select GUID database file to load"), currentDir, tr("Comma-separated values files (*.csv);;All files (*)")); - if (!path.isEmpty()) { - initGuidDatabase(path); - if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("New GUID database loaded"), tr("Apply new GUID database on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No)) - openImageFile(currentPath); - } -} - -void UEFITool::unloadGuidDatabase() -{ - initGuidDatabase(); - if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("GUID database unloaded"), tr("Apply changes on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No)) - openImageFile(currentPath); -} - -void UEFITool::loadDefaultGuidDatabase() -{ - initGuidDatabase(":/guids.csv"); - if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("Default GUID database loaded"), tr("Apply default GUID database on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No)) - openImageFile(currentPath); -} - -void UEFITool::exportDiscoveredGuids() -{ - GuidDatabase db = guidDatabaseFromTreeRecursive(model, model->index(0, 0)); - if (!db.empty()) { - QString path = QFileDialog::getSaveFileName(this, tr("Save parsed GUIDs to database"), currentPath + ".guids.csv", tr("Comma-separated values files (*.csv);;All files (*)")); - if (!path.isEmpty()) - guidDatabaseExportToFile(path, db); - } -} - -void UEFITool::generateReport() -{ - QString path = QFileDialog::getSaveFileName(this, tr("Save report to text file"), currentPath + ".report.txt", tr("Text files (*.txt);;All files (*)")); - if (!path.isEmpty()) { - std::vector report = ffsReport->generate(); - if (report.size()) { - QFile file; - file.setFileName(path); - if (file.open(QFile::Text | QFile::WriteOnly)) { - for (size_t i = 0; i < report.size(); i++) { - file.write(report[i].toLatin1().append('\n')); - } - file.close(); + QListWidgetItem* item = new QListWidgetItem(msg.first, NULL, 0); + item->setData(Qt::UserRole, QByteArray((const char*)&msg.second, sizeof(msg.second)));; + ui->finderMessagesListWidget->addItem(item); } + + ui->messagesTabWidget->setTabEnabled(TAB_SEARCH, true); + ui->messagesTabWidget->setCurrentIndex(TAB_SEARCH); + ui->finderMessagesListWidget->scrollToBottom(); } - } -} + + void UEFITool::showBuilderMessages() + { + ui->builderMessagesListWidget->clear(); + if (!ffsBuilder) + return; + + std::vector > messages = ffsBuilder->getMessages(); + +#if QT_VERSION_MAJOR < 6 + std::pair msg; + + foreach (msg, messages) { +#else + for (const auto &msg : messages) { +#endif + QListWidgetItem* item = new QListWidgetItem(msg.first, NULL, 0); + item->setData(Qt::UserRole, QByteArray((const char*)&msg.second, sizeof(msg.second))); + ui->builderMessagesListWidget->addItem(item); + } + + ui->messagesTabWidget->setTabEnabled(TAB_BUILDER, true); + ui->messagesTabWidget->setCurrentIndex(TAB_BUILDER); + ui->builderMessagesListWidget->scrollToBottom(); + } + + void UEFITool::scrollTreeView(QListWidgetItem* item) + { + QByteArray second = item->data(Qt::UserRole).toByteArray(); + QModelIndex *index = (QModelIndex *)second.data(); + if (index && index->isValid()) { + ui->structureTreeView->scrollTo(*index, QAbstractItemView::PositionAtCenter); + ui->structureTreeView->selectionModel()->select(*index, QItemSelectionModel::Select | QItemSelectionModel::Rows | QItemSelectionModel::Clear); + } + } + + void UEFITool::scrollTreeView(QTableWidgetItem* item) + { + QByteArray second = item->data(Qt::UserRole).toByteArray(); + QModelIndex *index = (QModelIndex *)second.data(); + if (index && index->isValid()) { + ui->structureTreeView->scrollTo(*index, QAbstractItemView::PositionAtCenter); + ui->structureTreeView->selectionModel()->select(*index, QItemSelectionModel::Select | QItemSelectionModel::Rows | QItemSelectionModel::Clear); + } + } + + void UEFITool::contextMenuEvent(QContextMenuEvent* event) + { + // The checks involving underMouse do not work well enough on macOS, and result in right-click sometimes + // not showing any context menu at all. Most likely it is a bug in Qt, which does not affect other systems. + // For this reason we reimplement this manually. + if (ui->parserMessagesListWidget->rect().contains(ui->parserMessagesListWidget->mapFromGlobal(event->globalPos())) || + ui->finderMessagesListWidget->rect().contains(ui->finderMessagesListWidget->mapFromGlobal(event->globalPos())) || + ui->builderMessagesListWidget->rect().contains(ui->builderMessagesListWidget->mapFromGlobal(event->globalPos()))) { + ui->menuMessageActions->exec(event->globalPos()); + return; + } + + + if (!ui->structureTreeView->rect().contains(ui->structureTreeView->mapFromGlobal(event->globalPos()))) + return; + + QPoint pt = event->pos(); + QModelIndex index = ui->structureTreeView->indexAt(ui->structureTreeView->viewport()->mapFrom(this, pt)); + if (!index.isValid()) { + return; + } + + switch (model->type(index)) + { + case Types::Capsule: ui->menuCapsuleActions->exec(event->globalPos()); break; + case Types::Image: ui->menuImageActions->exec(event->globalPos()); break; + case Types::Region: ui->menuRegionActions->exec(event->globalPos()); break; + case Types::Padding: ui->menuPaddingActions->exec(event->globalPos()); break; + case Types::Volume: ui->menuVolumeActions->exec(event->globalPos()); break; + case Types::File: ui->menuFileActions->exec(event->globalPos()); break; + case Types::Section: ui->menuSectionActions->exec(event->globalPos()); break; + case Types::VssStore: + case Types::Vss2Store: + case Types::FdcStore: + case Types::FsysStore: + case Types::EvsaStore: + case Types::FtwStore: + case Types::FlashMapStore: + case Types::CmdbStore: + case Types::FptStore: + case Types::CpdStore: + case Types::BpdtStore: ui->menuStoreActions->exec(event->globalPos()); break; + case Types::FreeSpace: break; // No menu needed for FreeSpace item + default: ui->menuEntryActions->exec(event->globalPos()); break; + } + } + + void UEFITool::readSettings() + { + QSettings settings(this); + restoreGeometry(settings.value("mainWindow/geometry").toByteArray()); + restoreState(settings.value("mainWindow/windowState").toByteArray()); + QList horList, vertList; + horList.append(settings.value("mainWindow/treeWidth", 600).toInt()); + horList.append(settings.value("mainWindow/infoWidth", 180).toInt()); + vertList.append(settings.value("mainWindow/treeHeight", 400).toInt()); + vertList.append(settings.value("mainWindow/messageHeight", 180).toInt()); + ui->infoSplitter->setSizes(horList); + ui->messagesSplitter->setSizes(vertList); + ui->structureTreeView->setColumnWidth(0, settings.value("tree/columnWidth0", ui->structureTreeView->columnWidth(0)).toInt()); + ui->structureTreeView->setColumnWidth(1, settings.value("tree/columnWidth1", ui->structureTreeView->columnWidth(1)).toInt()); + ui->structureTreeView->setColumnWidth(2, settings.value("tree/columnWidth2", ui->structureTreeView->columnWidth(2)).toInt()); + ui->structureTreeView->setColumnWidth(3, settings.value("tree/columnWidth3", ui->structureTreeView->columnWidth(3)).toInt()); + markingEnabled = settings.value("tree/markingEnabled", true).toBool(); + ui->actionToggleBootGuardMarking->setChecked(markingEnabled); + + // Set monospace font for some controls + QString fontName; + int fontSize; +#if defined Q_OS_OSX + fontName = settings.value("mainWindow/fontName", QString("Menlo")).toString(); + fontSize = settings.value("mainWindow/fontSize", 10).toInt(); +#elif defined Q_OS_WIN + fontName = settings.value("mainWindow/fontName", QString("Consolas")).toString(); + fontSize = settings.value("mainWindow/fontSize", 9).toInt(); +#else + fontName = settings.value("mainWindow/fontName", QString("Courier New")).toString(); + fontSize = settings.value("mainWindow/fontSize", 10).toInt(); +#endif + currentFont = QFont(fontName, fontSize); + ui->infoEdit->setFont(currentFont); + ui->parserMessagesListWidget->setFont(currentFont); + ui->finderMessagesListWidget->setFont(currentFont); + ui->builderMessagesListWidget->setFont(currentFont); + ui->fitTableWidget->setFont(currentFont); + ui->securityEdit->setFont(currentFont); + ui->structureTreeView->setFont(currentFont); + searchDialog->ui->guidEdit->setFont(currentFont); + searchDialog->ui->hexEdit->setFont(currentFont); + hexViewDialog->setFont(currentFont); + goToAddressDialog->ui->hexSpinBox->setFont(currentFont); + goToBaseDialog->ui->hexSpinBox->setFont(currentFont); + } + + void UEFITool::writeSettings() + { + QSettings settings(this); + settings.setValue("mainWindow/geometry", saveGeometry()); + settings.setValue("mainWindow/windowState", saveState()); + settings.setValue("mainWindow/treeWidth", ui->structureGroupBox->width()); + settings.setValue("mainWindow/infoWidth", ui->infoGroupBox->width()); + settings.setValue("mainWindow/treeHeight", ui->structureGroupBox->height()); + settings.setValue("mainWindow/messageHeight", ui->messagesTabWidget->height()); + settings.setValue("tree/columnWidth0", ui->structureTreeView->columnWidth(0)); + settings.setValue("tree/columnWidth1", ui->structureTreeView->columnWidth(1)); + settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2)); + settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3)); + settings.setValue("tree/markingEnabled", markingEnabled); + settings.setValue("mainWindow/fontName", currentFont.family()); + settings.setValue("mainWindow/fontSize", currentFont.pointSize()); + } + + void UEFITool::showFitTable() + { + std::vector, UModelIndex> > fitTable = ffsParser->getFitTable(); + if (fitTable.empty()) { + // Disable FIT tab + ui->messagesTabWidget->setTabEnabled(TAB_FIT, false); + return; + } + + // Enable FIT tab + ui->messagesTabWidget->setTabEnabled(TAB_FIT, true); + + // Set up the FIT table + ui->fitTableWidget->clear(); + ui->fitTableWidget->setRowCount((int)fitTable.size()); + ui->fitTableWidget->setColumnCount(6); + ui->fitTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Address") << tr("Size") << tr("Version") << tr("Checksum") << tr("Type") << tr("Information")); + ui->fitTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->fitTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->fitTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); + ui->fitTableWidget->horizontalHeader()->setStretchLastSection(true); + + // Add all data to the table widget + for (size_t i = 0; i < fitTable.size(); i++) { + for (UINT8 j = 0; j < 6; j++) { + QTableWidgetItem* item = new QTableWidgetItem(fitTable[i].first[j]); + item->setData(Qt::UserRole, QByteArray((const char*)&fitTable[i].second, sizeof(fitTable[i].second))); + ui->fitTableWidget->setItem((int)i, j, item); + } + } + + ui->fitTableWidget->resizeColumnsToContents(); + ui->fitTableWidget->resizeRowsToContents(); + ui->messagesTabWidget->setCurrentIndex(TAB_FIT); + } + + void UEFITool::showSecurityInfo() + { + // Get security info + UString secInfo = ffsParser->getSecurityInfo(); + if (secInfo.isEmpty()) { + ui->messagesTabWidget->setTabEnabled(TAB_SECURITY, false); + return; + } + + ui->messagesTabWidget->setTabEnabled(TAB_SECURITY, true); + ui->securityEdit->setPlainText(secInfo); + ui->messagesTabWidget->setCurrentIndex(TAB_SECURITY); + } + + void UEFITool::currentTabChanged(int index) + { + U_UNUSED_PARAMETER(index); + + ui->menuMessageActions->setEnabled(false); + ui->actionMessagesCopy->setEnabled(false); + ui->actionMessagesCopyAll->setEnabled(false); + ui->actionMessagesClear->setEnabled(false); + } + + void UEFITool::loadGuidDatabase() + { + QString path = QFileDialog::getOpenFileName(this, tr("Select GUID database file to load"), currentDir, tr("Comma-separated values files (*.csv);;All files (*)")); + if (!path.isEmpty()) { + initGuidDatabase(path); + if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("New GUID database loaded"), tr("Apply new GUID database on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No)) + openImageFile(currentPath); + } + } + + void UEFITool::unloadGuidDatabase() + { + initGuidDatabase(); + if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("GUID database unloaded"), tr("Apply changes on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No)) + openImageFile(currentPath); + } + + void UEFITool::loadDefaultGuidDatabase() + { + initGuidDatabase(":/guids.csv"); + if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("Default GUID database loaded"), tr("Apply default GUID database on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No)) + openImageFile(currentPath); + } + + void UEFITool::exportDiscoveredGuids() + { + GuidDatabase db = guidDatabaseFromTreeRecursive(model, model->index(0, 0)); + if (!db.empty()) { + QString path = QFileDialog::getSaveFileName(this, tr("Save parsed GUIDs to database"), currentPath + ".guids.csv", tr("Comma-separated values files (*.csv);;All files (*)")); + if (!path.isEmpty()) + guidDatabaseExportToFile(path, db); + } + } + + void UEFITool::generateReport() + { + QString path = QFileDialog::getSaveFileName(this, tr("Save report to text file"), currentPath + ".report.txt", tr("Text files (*.txt);;All files (*)")); + if (!path.isEmpty()) { + std::vector report = ffsReport->generate(); + if (report.size()) { + QFile file; + file.setFileName(path); + if (file.open(QFile::Text | QFile::WriteOnly)) { + for (size_t i = 0; i < report.size(); i++) { + file.write(report[i].toLatin1().append('\n')); + } + file.close(); + } + } + } + } diff --git a/UEFITool/uefitool_main.cpp b/UEFITool/uefitool_main.cpp index 7114935..d9b8907 100644 --- a/UEFITool/uefitool_main.cpp +++ b/UEFITool/uefitool_main.cpp @@ -1,15 +1,15 @@ /* uefitool_main.cpp - - Copyright (c) 2018, LongSoft. 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, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - */ + + Copyright (c) 2018, LongSoft. 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include #include @@ -18,10 +18,10 @@ class UEFIToolApplication : public QApplication { UEFITool* tool; - + public: UEFIToolApplication(int &argc, char **argv) - : QApplication(argc, argv) + : QApplication(argc, argv) { setOrganizationName("LongSoft"); setOrganizationDomain("longsoft.org"); @@ -40,7 +40,7 @@ public: QFileOpenEvent *openEvent = static_cast(event); tool->openImageFile(openEvent->file()); } - + return QApplication::event(event); } diff --git a/common/descriptor.cpp b/common/descriptor.cpp index 080127b..caa6fde 100644 --- a/common/descriptor.cpp +++ b/common/descriptor.cpp @@ -1,14 +1,14 @@ /* descriptor.cpp - -Copyright (c) 2015, 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. -*/ + + Copyright (c) 2015, 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. + */ #include "descriptor.h" @@ -44,207 +44,207 @@ UString jedecIdToUString(UINT8 vendorId, UINT8 deviceId0, UINT8 deviceId1) { UINT32 jedecId = (UINT32)deviceId1 + ((UINT32)deviceId0 << 8) + ((UINT32)vendorId << 16); switch (jedecId) { - // Winbond - case 0xEF3010: return UString("Winbond W25X05"); - case 0xEF3011: return UString("Winbond W25X10"); - case 0xEF3012: return UString("Winbond W25X20"); - case 0xEF3013: return UString("Winbond W25X40"); - case 0xEF3014: return UString("Winbond W25X80"); - case 0xEF3015: return UString("Winbond W25X16"); - case 0xEF3016: return UString("Winbond W25X32"); - case 0xEF3017: return UString("Winbond W25X64"); - case 0xEF4012: return UString("Winbond W25Q20"); - case 0xEF4013: return UString("Winbond W25Q40"); - case 0xEF4014: return UString("Winbond W25Q80"); - case 0xEF4015: return UString("Winbond W25Q16"); - case 0xEF4016: return UString("Winbond W25Q32"); - case 0xEF4017: return UString("Winbond W25Q64"); - case 0xEF4018: return UString("Winbond W25Q128"); - case 0xEF4019: return UString("Winbond W25Q256"); - case 0xEF6011: return UString("Winbond W25Q10"); - case 0xEF6012: return UString("Winbond W25Q20"); - case 0xEF6013: return UString("Winbond W25Q40"); - case 0xEF6014: return UString("Winbond W25Q80"); - case 0xEF6015: return UString("Winbond W25Q16"); - case 0xEF6016: return UString("Winbond W25Q32"); - case 0xEF6017: return UString("Winbond W25Q64"); - case 0xEF6018: return UString("Winbond W25Q128"); - case 0xEF6019: return UString("Winbond W25Q256"); - case 0xEF7118: return UString("Winbond W25M256"); - case 0xEF7119: return UString("Winbond W25M512"); - - // Macronix - case 0xC22013: return UString("Macronix MX25L40"); - case 0xC22014: return UString("Macronix MX25L80"); - case 0xC22015: return UString("Macronix MX25L16"); - case 0xC22016: return UString("Macronix MX25U16"); - case 0xC22017: return UString("Macronix MX25L64"); - case 0xC22018: return UString("Macronix MX25L128"); - case 0xC22019: return UString("Macronix MX25L256"); - case 0xC2201A: return UString("Macronix MX66L512"); - case 0xC22415: return UString("Macronix MX25L16"); - case 0xC22515: return UString("Macronix MX25L16"); - case 0xC22534: return UString("Macronix MX25U80"); - case 0xC22535: return UString("Macronix MX25U16"); - case 0xC22536: return UString("Macronix MX25U32"); - case 0xC22537: return UString("Macronix MX25U64"); - case 0xC22538: return UString("Macronix MX25U128"); - case 0xC22539: return UString("Macronix MX25U256"); - case 0xC2253A: return UString("Macronix MX25U512"); - case 0xC22617: return UString("Macronix MX25L64"); - case 0xC22618: return UString("Macronix MX25L128"); - case 0xC25E16: return UString("Macronix MX25L32"); - case 0xC29517: return UString("Macronix MX25L64"); - - // Micron - case 0x202014: return UString("Micron M25P80"); - case 0x202015: return UString("Micron M25P16"); - case 0x202016: return UString("Micron M25P32"); - case 0x202017: return UString("Micron M25P64"); - case 0x202018: return UString("Micron M25P128"); - case 0x204011: return UString("Micron M45PE10"); - case 0x204012: return UString("Micron M45PE20"); - case 0x204013: return UString("Micron M45PE40"); - case 0x204014: return UString("Micron M45PE80"); - case 0x204015: return UString("Micron M45PE16"); - case 0x204017: return UString("Micron XM25QH64C"); - case 0x204018: return UString("Micron XM25QH128C"); - case 0x204019: return UString("Micron XM25QH256C"); - case 0x207114: return UString("Micron M25PX80"); - case 0x207115: return UString("Micron M25PX16"); - case 0x207116: return UString("Micron M25PX32"); - case 0x207117: return UString("Micron M25PX64"); - case 0x208011: return UString("Micron M25PE10"); - case 0x208012: return UString("Micron M25PE20"); - case 0x208013: return UString("Micron M25PE40"); - case 0x208014: return UString("Micron M25PE80"); - case 0x208015: return UString("Micron M25PE16"); - case 0x20BA15: return UString("Micron N25Q016"); - case 0x20BA16: return UString("Micron N25Q032"); - case 0x20BA17: return UString("Micron N25Q064"); - case 0x20BA18: return UString("Micron N25Q128"); - case 0x20BA19: return UString("Micron N25Q256"); - case 0x20BA20: return UString("Micron N25Q512"); - case 0x20BA21: return UString("Micron N25Q00A"); - case 0x20BB15: return UString("Micron N25Q016"); - case 0x20BB16: return UString("Micron N25Q032"); - case 0x20BB17: return UString("Micron N25Q064"); - case 0x20BB18: return UString("Micron MT25Q128"); - case 0x20BB19: return UString("Micron MT25Q256"); - case 0x20BB20: return UString("Micron MT25Q512"); - - // Intel - case 0x898911: return UString("Intel 25F160S33B8"); - case 0x898912: return UString("Intel 25F320S33B8"); - case 0x898913: return UString("Intel 25F640S33B8"); - case 0x898915: return UString("Intel 25F160S33T8"); - case 0x898916: return UString("Intel 25F320S33T8"); - case 0x898917: return UString("Intel 25F640S33T8"); - - // Atmel / Adesto - case 0x1F3217: return UString("Atmel AT25SF641"); - case 0x1F4216: return UString("Atmel AT25SL321"); - case 0x1F4218: return UString("Atmel AT25SL128A"); - case 0x1F4317: return UString("Atmel AT25SL641"); - case 0x1F4500: return UString("Atmel AT26DF081"); - case 0x1F4501: return UString("Atmel AT26DF081A"); - case 0x1F4502: return UString("Atmel AT25DF081"); - case 0x1F4600: return UString("Atmel AT26DF161"); - case 0x1F4601: return UString("Atmel AT26DF161A"); - case 0x1F4602: return UString("Atmel AT25DF161"); - case 0x1F4700: return UString("Atmel AT25DF321"); - case 0x1F4701: return UString("Atmel AT25DF321A"); - case 0x1F4800: return UString("Atmel AT25DF641"); - case 0x1F7018: return UString("Atmel AT25QF128"); - case 0x1F8600: return UString("Atmel AT25DQ161"); - case 0x1F8800: return UString("Atmel AT25DQ641"); - - // Microchip - case 0xBF2541: return UString("Microchip SST25VF016B"); - case 0xBF254A: return UString("Microchip SST25VF032B"); - case 0xBF258D: return UString("Microchip SST25VF040B"); - case 0xBF258E: return UString("Microchip SST25VF080B"); - case 0xBF254B: return UString("Microchip SST25VF064C"); - - // EON / ESMT - case 0x1C3013: return UString("EON EN25Q40"); - case 0x1C3014: return UString("EON EN25Q80"); - case 0x1C3015: return UString("EON EN25Q16"); - case 0x1C3016: return UString("EON EN25Q32"); - case 0x1C3017: return UString("EON EN25Q64"); - case 0x1C3018: return UString("EON EN25Q128"); - case 0x1C3114: return UString("EON EN25F80"); - case 0x1C3115: return UString("EON EN25F16"); - case 0x1C3116: return UString("EON EN25F32"); - case 0x1C3117: return UString("EON EN25F64"); - case 0x1C3811: return UString("EON EN25S10"); - case 0x1C3812: return UString("EON EN25S20"); - case 0x1C3813: return UString("EON EN25S40"); - case 0x1C3814: return UString("EON EN25S80"); - case 0x1C3815: return UString("EON EN25S16"); - case 0x1C3816: return UString("EON EN25S32"); - case 0x1C3817: return UString("EON EN25S64"); - case 0x1C7014: return UString("EON EN25QH80"); - case 0x1C7015: return UString("EON EN25QH16"); - case 0x1C7016: return UString("EON EN25QH32"); - case 0x1C7017: return UString("EON EN25QH64"); - case 0x1C7018: return UString("EON EN25QH128"); - case 0x1C7019: return UString("EON EN25QH256"); - - // GigaDevice - case 0xC84014: return UString("GigaDevice GD25x80"); - case 0xC84015: return UString("GigaDevice GD25x16"); - case 0xC84016: return UString("GigaDevice GD25x32"); - case 0xC84017: return UString("GigaDevice GD25x64"); - case 0xC84018: return UString("GigaDevice GD25x128"); - case 0xC84019: return UString("GigaDevice GD25x256C"); - case 0xC86015: return UString("GigaDevice GD25LQ16V"); - case 0xC86017: return UString("GigaDevice GD25Lx64"); - case 0xC86018: return UString("GigaDevice GD25Lx128"); - case 0xC86019: return UString("GigaDevice GD25LQ256C"); - - // Fidelix - case 0xF83215: return UString("Fidelix FM25Q16"); - case 0xF83216: return UString("Fidelix FM25Q32"); - case 0xF83217: return UString("Fidelix FM25Q64"); - case 0xF83218: return UString("Fidelix FM25Q128"); - - // Spansion - case 0x014015: return UString("Spansion S25FL116K"); - case 0x014016: return UString("Spansion S25FL132K"); - case 0x014017: return UString("Spansion S25FL164K"); - - // AMIC Technology - case 0x373015: return UString("AMIC A25L016"); - case 0x373016: return UString("AMIC A25L032"); - case 0x374015: return UString("AMIC A25LQ16"); - case 0x374016: return UString("AMIC A25LQ32A"); - - // PMC - case 0x9DF713: return UString("PMC Pm25LV080B"); - case 0x9DF714: return UString("PMC Pm25LV016B"); - case 0x9DF744: return UString("PMC Pm25LQ080C"); - case 0x9DF745: return UString("PMC Pm25LQ016C"); - case 0x9DF746: return UString("PMC Pm25LQ032C"); - case 0x9DF77B: return UString("PMC Pm25LV512A"); - case 0x9DF77C: return UString("PMC Pm25LV010A"); - case 0x9DF77D: return UString("PMC Pm25LV020"); - case 0x9DF77E: return UString("PMC Pm25LV040"); - - // ISSI - case 0x9D6014: return UString("ISSI Ix25LP080"); - case 0x9D6015: return UString("ISSI Ix25LP016"); - case 0x9D6016: return UString("ISSI Ix25LP032"); - case 0x9D6017: return UString("ISSI Ix25LP064"); - case 0x9D6018: return UString("ISSI Ix25LP128"); - case 0x9D6019: return UString("ISSI Ix25LP256"); - case 0x9D7014: return UString("ISSI Ix25WP080"); - case 0x9D7015: return UString("ISSI Ix25WP016"); - case 0x9D7016: return UString("ISSI Ix25WP032"); - case 0x9D7017: return UString("ISSI Ix25WP064"); - case 0x9D7018: return UString("ISSI Ix25WP128"); - case 0x9D7019: return UString("ISSI Ix25WP256"); + // Winbond + case 0xEF3010: return UString("Winbond W25X05"); + case 0xEF3011: return UString("Winbond W25X10"); + case 0xEF3012: return UString("Winbond W25X20"); + case 0xEF3013: return UString("Winbond W25X40"); + case 0xEF3014: return UString("Winbond W25X80"); + case 0xEF3015: return UString("Winbond W25X16"); + case 0xEF3016: return UString("Winbond W25X32"); + case 0xEF3017: return UString("Winbond W25X64"); + case 0xEF4012: return UString("Winbond W25Q20"); + case 0xEF4013: return UString("Winbond W25Q40"); + case 0xEF4014: return UString("Winbond W25Q80"); + case 0xEF4015: return UString("Winbond W25Q16"); + case 0xEF4016: return UString("Winbond W25Q32"); + case 0xEF4017: return UString("Winbond W25Q64"); + case 0xEF4018: return UString("Winbond W25Q128"); + case 0xEF4019: return UString("Winbond W25Q256"); + case 0xEF6011: return UString("Winbond W25Q10"); + case 0xEF6012: return UString("Winbond W25Q20"); + case 0xEF6013: return UString("Winbond W25Q40"); + case 0xEF6014: return UString("Winbond W25Q80"); + case 0xEF6015: return UString("Winbond W25Q16"); + case 0xEF6016: return UString("Winbond W25Q32"); + case 0xEF6017: return UString("Winbond W25Q64"); + case 0xEF6018: return UString("Winbond W25Q128"); + case 0xEF6019: return UString("Winbond W25Q256"); + case 0xEF7118: return UString("Winbond W25M256"); + case 0xEF7119: return UString("Winbond W25M512"); + + // Macronix + case 0xC22013: return UString("Macronix MX25L40"); + case 0xC22014: return UString("Macronix MX25L80"); + case 0xC22015: return UString("Macronix MX25L16"); + case 0xC22016: return UString("Macronix MX25U16"); + case 0xC22017: return UString("Macronix MX25L64"); + case 0xC22018: return UString("Macronix MX25L128"); + case 0xC22019: return UString("Macronix MX25L256"); + case 0xC2201A: return UString("Macronix MX66L512"); + case 0xC22415: return UString("Macronix MX25L16"); + case 0xC22515: return UString("Macronix MX25L16"); + case 0xC22534: return UString("Macronix MX25U80"); + case 0xC22535: return UString("Macronix MX25U16"); + case 0xC22536: return UString("Macronix MX25U32"); + case 0xC22537: return UString("Macronix MX25U64"); + case 0xC22538: return UString("Macronix MX25U128"); + case 0xC22539: return UString("Macronix MX25U256"); + case 0xC2253A: return UString("Macronix MX25U512"); + case 0xC22617: return UString("Macronix MX25L64"); + case 0xC22618: return UString("Macronix MX25L128"); + case 0xC25E16: return UString("Macronix MX25L32"); + case 0xC29517: return UString("Macronix MX25L64"); + + // Micron + case 0x202014: return UString("Micron M25P80"); + case 0x202015: return UString("Micron M25P16"); + case 0x202016: return UString("Micron M25P32"); + case 0x202017: return UString("Micron M25P64"); + case 0x202018: return UString("Micron M25P128"); + case 0x204011: return UString("Micron M45PE10"); + case 0x204012: return UString("Micron M45PE20"); + case 0x204013: return UString("Micron M45PE40"); + case 0x204014: return UString("Micron M45PE80"); + case 0x204015: return UString("Micron M45PE16"); + case 0x204017: return UString("Micron XM25QH64C"); + case 0x204018: return UString("Micron XM25QH128C"); + case 0x204019: return UString("Micron XM25QH256C"); + case 0x207114: return UString("Micron M25PX80"); + case 0x207115: return UString("Micron M25PX16"); + case 0x207116: return UString("Micron M25PX32"); + case 0x207117: return UString("Micron M25PX64"); + case 0x208011: return UString("Micron M25PE10"); + case 0x208012: return UString("Micron M25PE20"); + case 0x208013: return UString("Micron M25PE40"); + case 0x208014: return UString("Micron M25PE80"); + case 0x208015: return UString("Micron M25PE16"); + case 0x20BA15: return UString("Micron N25Q016"); + case 0x20BA16: return UString("Micron N25Q032"); + case 0x20BA17: return UString("Micron N25Q064"); + case 0x20BA18: return UString("Micron N25Q128"); + case 0x20BA19: return UString("Micron N25Q256"); + case 0x20BA20: return UString("Micron N25Q512"); + case 0x20BA21: return UString("Micron N25Q00A"); + case 0x20BB15: return UString("Micron N25Q016"); + case 0x20BB16: return UString("Micron N25Q032"); + case 0x20BB17: return UString("Micron N25Q064"); + case 0x20BB18: return UString("Micron MT25Q128"); + case 0x20BB19: return UString("Micron MT25Q256"); + case 0x20BB20: return UString("Micron MT25Q512"); + + // Intel + case 0x898911: return UString("Intel 25F160S33B8"); + case 0x898912: return UString("Intel 25F320S33B8"); + case 0x898913: return UString("Intel 25F640S33B8"); + case 0x898915: return UString("Intel 25F160S33T8"); + case 0x898916: return UString("Intel 25F320S33T8"); + case 0x898917: return UString("Intel 25F640S33T8"); + + // Atmel / Adesto + case 0x1F3217: return UString("Atmel AT25SF641"); + case 0x1F4216: return UString("Atmel AT25SL321"); + case 0x1F4218: return UString("Atmel AT25SL128A"); + case 0x1F4317: return UString("Atmel AT25SL641"); + case 0x1F4500: return UString("Atmel AT26DF081"); + case 0x1F4501: return UString("Atmel AT26DF081A"); + case 0x1F4502: return UString("Atmel AT25DF081"); + case 0x1F4600: return UString("Atmel AT26DF161"); + case 0x1F4601: return UString("Atmel AT26DF161A"); + case 0x1F4602: return UString("Atmel AT25DF161"); + case 0x1F4700: return UString("Atmel AT25DF321"); + case 0x1F4701: return UString("Atmel AT25DF321A"); + case 0x1F4800: return UString("Atmel AT25DF641"); + case 0x1F7018: return UString("Atmel AT25QF128"); + case 0x1F8600: return UString("Atmel AT25DQ161"); + case 0x1F8800: return UString("Atmel AT25DQ641"); + + // Microchip + case 0xBF2541: return UString("Microchip SST25VF016B"); + case 0xBF254A: return UString("Microchip SST25VF032B"); + case 0xBF258D: return UString("Microchip SST25VF040B"); + case 0xBF258E: return UString("Microchip SST25VF080B"); + case 0xBF254B: return UString("Microchip SST25VF064C"); + + // EON / ESMT + case 0x1C3013: return UString("EON EN25Q40"); + case 0x1C3014: return UString("EON EN25Q80"); + case 0x1C3015: return UString("EON EN25Q16"); + case 0x1C3016: return UString("EON EN25Q32"); + case 0x1C3017: return UString("EON EN25Q64"); + case 0x1C3018: return UString("EON EN25Q128"); + case 0x1C3114: return UString("EON EN25F80"); + case 0x1C3115: return UString("EON EN25F16"); + case 0x1C3116: return UString("EON EN25F32"); + case 0x1C3117: return UString("EON EN25F64"); + case 0x1C3811: return UString("EON EN25S10"); + case 0x1C3812: return UString("EON EN25S20"); + case 0x1C3813: return UString("EON EN25S40"); + case 0x1C3814: return UString("EON EN25S80"); + case 0x1C3815: return UString("EON EN25S16"); + case 0x1C3816: return UString("EON EN25S32"); + case 0x1C3817: return UString("EON EN25S64"); + case 0x1C7014: return UString("EON EN25QH80"); + case 0x1C7015: return UString("EON EN25QH16"); + case 0x1C7016: return UString("EON EN25QH32"); + case 0x1C7017: return UString("EON EN25QH64"); + case 0x1C7018: return UString("EON EN25QH128"); + case 0x1C7019: return UString("EON EN25QH256"); + + // GigaDevice + case 0xC84014: return UString("GigaDevice GD25x80"); + case 0xC84015: return UString("GigaDevice GD25x16"); + case 0xC84016: return UString("GigaDevice GD25x32"); + case 0xC84017: return UString("GigaDevice GD25x64"); + case 0xC84018: return UString("GigaDevice GD25x128"); + case 0xC84019: return UString("GigaDevice GD25x256C"); + case 0xC86015: return UString("GigaDevice GD25LQ16V"); + case 0xC86017: return UString("GigaDevice GD25Lx64"); + case 0xC86018: return UString("GigaDevice GD25Lx128"); + case 0xC86019: return UString("GigaDevice GD25LQ256C"); + + // Fidelix + case 0xF83215: return UString("Fidelix FM25Q16"); + case 0xF83216: return UString("Fidelix FM25Q32"); + case 0xF83217: return UString("Fidelix FM25Q64"); + case 0xF83218: return UString("Fidelix FM25Q128"); + + // Spansion + case 0x014015: return UString("Spansion S25FL116K"); + case 0x014016: return UString("Spansion S25FL132K"); + case 0x014017: return UString("Spansion S25FL164K"); + + // AMIC Technology + case 0x373015: return UString("AMIC A25L016"); + case 0x373016: return UString("AMIC A25L032"); + case 0x374015: return UString("AMIC A25LQ16"); + case 0x374016: return UString("AMIC A25LQ32A"); + + // PMC + case 0x9DF713: return UString("PMC Pm25LV080B"); + case 0x9DF714: return UString("PMC Pm25LV016B"); + case 0x9DF744: return UString("PMC Pm25LQ080C"); + case 0x9DF745: return UString("PMC Pm25LQ016C"); + case 0x9DF746: return UString("PMC Pm25LQ032C"); + case 0x9DF77B: return UString("PMC Pm25LV512A"); + case 0x9DF77C: return UString("PMC Pm25LV010A"); + case 0x9DF77D: return UString("PMC Pm25LV020"); + case 0x9DF77E: return UString("PMC Pm25LV040"); + + // ISSI + case 0x9D6014: return UString("ISSI Ix25LP080"); + case 0x9D6015: return UString("ISSI Ix25LP016"); + case 0x9D6016: return UString("ISSI Ix25LP032"); + case 0x9D6017: return UString("ISSI Ix25LP064"); + case 0x9D6018: return UString("ISSI Ix25LP128"); + case 0x9D6019: return UString("ISSI Ix25LP256"); + case 0x9D7014: return UString("ISSI Ix25WP080"); + case 0x9D7015: return UString("ISSI Ix25WP016"); + case 0x9D7016: return UString("ISSI Ix25WP032"); + case 0x9D7017: return UString("ISSI Ix25WP064"); + case 0x9D7018: return UString("ISSI Ix25WP128"); + case 0x9D7019: return UString("ISSI Ix25WP256"); } - + return UString("Unknown"); } diff --git a/common/ffs.cpp b/common/ffs.cpp index 85e792d..a2b5a8c 100644 --- a/common/ffs.cpp +++ b/common/ffs.cpp @@ -1,14 +1,14 @@ /* ffs.cpp - -Copyright (c) 2015, 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. -*/ + + Copyright (c) 2015, 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. + */ #include @@ -58,19 +58,19 @@ UString guidToUString(const EFI_GUID & guid, bool convertToString) if (!readableName.isEmpty()) return readableName; } - + return usprintf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - guid.Data1, - guid.Data2, - guid.Data3, - guid.Data4[0], - guid.Data4[1], - guid.Data4[2], - guid.Data4[3], - guid.Data4[4], - guid.Data4[5], - guid.Data4[6], - guid.Data4[7]); + guid.Data1, + guid.Data2, + guid.Data3, + guid.Data4[0], + guid.Data4[1], + guid.Data4[2], + guid.Data4[3], + guid.Data4[4], + guid.Data4[5], + guid.Data4[6], + guid.Data4[7]); } @@ -78,12 +78,12 @@ bool ustringToGuid(const UString & str, EFI_GUID & guid) { unsigned long p0; unsigned p1, p2, p3, p4, p5, p6, p7, p8, p9, p10; - + int err = std::sscanf(str.toLocal8Bit(), "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10); if (err == 0) return false; - + guid.Data1 = (UINT32)p0; guid.Data2 = (UINT16)p1; guid.Data3 = (UINT16)p2; @@ -95,7 +95,7 @@ bool ustringToGuid(const UString & str, EFI_GUID & guid) guid.Data4[5] = (UINT8)p8; guid.Data4[6] = (UINT8)p9; guid.Data4[7] = (UINT8)p10; - + return true; } diff --git a/common/ffsbuilder.cpp b/common/ffsbuilder.cpp index 6160532..dac3fa5 100644 --- a/common/ffsbuilder.cpp +++ b/common/ffsbuilder.cpp @@ -1,15 +1,15 @@ /* fssbuilder.cpp - -Copyright (c) 2015, 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2015, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "ffsbuilder.h" #include "descriptor.h" @@ -25,7 +25,7 @@ USTATUS FfsBuilder::erase(const UModelIndex & index, UByteArray & erased) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Try to get emptyByte value from item's parsing data UINT8 emptyByte = 0xFF; if (!model->hasEmptyParsingData(index)) { @@ -38,9 +38,9 @@ USTATUS FfsBuilder::erase(const UModelIndex & index, UByteArray & erased) emptyByte = pdata.emptyByte; } } - + erased = UByteArray(model->header(index).size() + model->body(index).size() + model->tail(index).size(), emptyByte); - + return U_SUCCESS; } @@ -49,7 +49,7 @@ USTATUS FfsBuilder::build(const UModelIndex & root, UByteArray & image) // Sanity check if (!root.isValid()) return U_INVALID_PARAMETER; - + if (model->type(root) == Types::Capsule) { return buildCapsule(root, image); } @@ -61,7 +61,7 @@ USTATUS FfsBuilder::build(const UModelIndex & root, UByteArray & image) return buildRawArea(root, image); } } - + return U_NOT_IMPLEMENTED; } @@ -70,27 +70,27 @@ USTATUS FfsBuilder::buildCapsule(const UModelIndex & index, UByteArray & capsule // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // No action if (model->action(index) == Actions::NoAction) { // Use original item data capsule = model->header(index) + model->body(index) + model->tail(index); return U_SUCCESS; } - + // Rebuild or Replace else if (model->action(index) == Actions::Rebuild - || model->action(index) == Actions::Replace) { + || model->action(index) == Actions::Replace) { if (model->rowCount(index)) { // Clear the supplied UByteArray capsule.clear(); - + // Right now there is only one capsule image element supported if (model->rowCount(index) != 1) { msg(usprintf("buildCapsule: building of capsules with %d items is not yet supported", model->rowCount(index)), index); return U_NOT_IMPLEMENTED; } - + // Build image UModelIndex imageIndex = index.model()->index(0, 0, index); UByteArray imageData; @@ -136,12 +136,12 @@ USTATUS FfsBuilder::buildCapsule(const UModelIndex & index, UByteArray & capsule } else capsule = model->body(index); - + // Build successful, append header and tail capsule = model->header(index) + capsule + model->tail(index); return U_SUCCESS; } - + msg(UString("buildCapsule: unexpected action " + actionTypeToUString(model->action(index))), index); return U_NOT_IMPLEMENTED; } @@ -166,15 +166,15 @@ USTATUS FfsBuilder::buildIntelImage(const UModelIndex & index, UByteArray & inte else if (model->action(index) == Actions::Rebuild) { // First child will always be descriptor for this type of image, and it's read only for now intelImage = model->header(index.model()->index(0, 0, index)) + model->body(index.model()->index(0, 0, index)) + model->tail(index.model()->index(0, 0, index)); - + // Process other regions for (int i = 1; i < model->rowCount(index); i++) { UModelIndex currentRegion = index.model()->index(i, 0, index); - + // Skip regions with Remove action if (model->action(currentRegion) == Actions::Remove) continue; - + // Check item type to be either region or padding UINT8 type = model->type(currentRegion); if (type == Types::Padding) { @@ -182,41 +182,41 @@ USTATUS FfsBuilder::buildIntelImage(const UModelIndex & index, UByteArray & inte intelImage += model->header(currentRegion) + model->body(currentRegion) + model->tail(currentRegion); continue; } - + // Check region subtype USTATUS result; UByteArray region; UINT8 regionType = model->subtype(currentRegion); switch (regionType) { - case Subtypes::BiosRegion: - case Subtypes::PdrRegion: - result = buildRawArea(currentRegion, region); - if (result) { - msg(UString("buildIntelImage: building of region ") + regionTypeToUString(regionType) + UString(" failed with error ") + errorCodeToUString(result), currentRegion); - return result; - } - break; - case Subtypes::MeRegion: - case Subtypes::GbeRegion: - case Subtypes::DevExp1Region: - case Subtypes::Bios2Region: - case Subtypes::MicrocodeRegion: - case Subtypes::EcRegion: - case Subtypes::DevExp2Region: - case Subtypes::IeRegion: - case Subtypes::Tgbe1Region: - case Subtypes::Tgbe2Region: - case Subtypes::Reserved1Region: - case Subtypes::Reserved2Region: - case Subtypes::PttRegion: - // Add region as is - region = model->header(currentRegion) + model->body(currentRegion); - break; - default: - msg(UString("buildIntelImage: unknown region type"), currentRegion); - return U_UNKNOWN_ITEM_TYPE; + case Subtypes::BiosRegion: + case Subtypes::PdrRegion: + result = buildRawArea(currentRegion, region); + if (result) { + msg(UString("buildIntelImage: building of region ") + regionTypeToUString(regionType) + UString(" failed with error ") + errorCodeToUString(result), currentRegion); + return result; + } + break; + case Subtypes::MeRegion: + case Subtypes::GbeRegion: + case Subtypes::DevExp1Region: + case Subtypes::Bios2Region: + case Subtypes::MicrocodeRegion: + case Subtypes::EcRegion: + case Subtypes::DevExp2Region: + case Subtypes::IeRegion: + case Subtypes::Tgbe1Region: + case Subtypes::Tgbe2Region: + case Subtypes::Reserved1Region: + case Subtypes::Reserved2Region: + case Subtypes::PttRegion: + // Add region as is + region = model->header(currentRegion) + model->body(currentRegion); + break; + default: + msg(UString("buildIntelImage: unknown region type"), currentRegion); + return U_UNKNOWN_ITEM_TYPE; } - + // Append the resulting region intelImage += region; } @@ -232,12 +232,12 @@ USTATUS FfsBuilder::buildIntelImage(const UModelIndex & index, UByteArray & inte msg(usprintf("buildIntelImage: new image size %Xh (%u) is smaller than the original %Xh (%u)", newSize, newSize, oldSize, oldSize), index); return U_INVALID_IMAGE; } - + // Build successful, append header and tail intelImage = model->header(index) + intelImage + model->tail(index); return U_SUCCESS; } - + msg(UString("buildIntelImage: unexpected action " + actionTypeToUString(model->action(index))), index); return U_NOT_IMPLEMENTED; } @@ -247,7 +247,7 @@ USTATUS FfsBuilder::buildRawArea(const UModelIndex & index, UByteArray & rawArea // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // No action required if (model->action(index) == Actions::NoAction) { rawArea = model->header(index) + model->body(index) + model->tail(index); @@ -260,12 +260,12 @@ USTATUS FfsBuilder::buildRawArea(const UModelIndex & index, UByteArray & rawArea } // Rebuild or Replace else if (model->action(index) == Actions::Rebuild - || model->action(index) == Actions::Replace) { + || model->action(index) == Actions::Replace) { // Rebuild if there is at least 1 child if (model->rowCount(index)) { // Clear the supplied UByteArray rawArea.clear(); - + // Build children for (int i = 0; i < model->rowCount(index); i++) { USTATUS result = U_SUCCESS; @@ -291,7 +291,7 @@ USTATUS FfsBuilder::buildRawArea(const UModelIndex & index, UByteArray & rawArea // Append current data rawArea += currentData; } - + // Check size of new raw area, it must be same as original one UINT32 newSize = (UINT32)rawArea.size(); UINT32 oldSize = (UINT32)model->body(index).size(); @@ -308,12 +308,12 @@ USTATUS FfsBuilder::buildRawArea(const UModelIndex & index, UByteArray & rawArea else { rawArea = model->body(index); } - + // Build successful, add header if needed rawArea = model->header(index) + rawArea + model->tail(index); return U_SUCCESS; } - + msg(UString("buildRawArea: unexpected action " + actionTypeToUString(model->action(index))), index); return U_NOT_IMPLEMENTED; } @@ -323,7 +323,7 @@ USTATUS FfsBuilder::buildPadding(const UModelIndex & index, UByteArray & padding // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // No action required if (model->action(index) == Actions::NoAction) { padding = model->header(index) + model->body(index) + model->tail(index); @@ -338,7 +338,7 @@ USTATUS FfsBuilder::buildPadding(const UModelIndex & index, UByteArray & padding else if (model->action(index) == Actions::Erase) { return erase(index, padding); } - + msg(UString("buildPadding: unexpected action " + actionTypeToUString(model->action(index))), index); return U_NOT_IMPLEMENTED; } @@ -348,7 +348,7 @@ USTATUS FfsBuilder::buildNonUefiData(const UModelIndex & index, UByteArray & dat // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // No action required if (model->action(index) == Actions::NoAction) { data = model->header(index) + model->body(index) + model->tail(index); @@ -363,9 +363,9 @@ USTATUS FfsBuilder::buildNonUefiData(const UModelIndex & index, UByteArray & dat else if (model->action(index) == Actions::Erase) { return erase(index, data); } - + // TODO: rebuild properly - + msg(UString("buildNoUefiData: unexpected action " + actionTypeToUString(model->action(index))), index); return U_NOT_IMPLEMENTED; } @@ -375,7 +375,7 @@ USTATUS FfsBuilder::buildFreeSpace(const UModelIndex & index, UByteArray & freeS // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // No actions possible for free space freeSpace = model->header(index) + model->body(index) + model->tail(index); return U_SUCCESS; @@ -385,7 +385,7 @@ USTATUS FfsBuilder::buildVolume(const UModelIndex & index, UByteArray & volume) { U_UNUSED_PARAMETER(index); U_UNUSED_PARAMETER(volume); - + return U_NOT_IMPLEMENTED; } @@ -393,7 +393,7 @@ USTATUS FfsBuilder::buildPadFile(const UModelIndex & index, UByteArray & padFile { U_UNUSED_PARAMETER(index); U_UNUSED_PARAMETER(padFile); - + return U_NOT_IMPLEMENTED; } @@ -401,7 +401,7 @@ USTATUS FfsBuilder::buildFile(const UModelIndex & index, UByteArray & file) { U_UNUSED_PARAMETER(index); U_UNUSED_PARAMETER(file); - + return U_NOT_IMPLEMENTED; } @@ -409,7 +409,7 @@ USTATUS FfsBuilder::buildSection(const UModelIndex & index, UByteArray & section { U_UNUSED_PARAMETER(index); U_UNUSED_PARAMETER(section); - + return U_NOT_IMPLEMENTED; } diff --git a/common/ffsops.cpp b/common/ffsops.cpp index f1b2093..2d6e5be 100644 --- a/common/ffsops.cpp +++ b/common/ffsops.cpp @@ -1,15 +1,15 @@ /* fssops.cpp - -Copyright (c) 2015, 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2015, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "ffsops.h" #include "ffs.h" @@ -20,10 +20,10 @@ USTATUS FfsOperations::extract(const UModelIndex & index, UString & name, UByteA // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Default name name = uniqueItemName(index); - + // Get extracted data if (mode == EXTRACT_MODE_AS_IS) { // Extract as is, with header body and tail @@ -45,18 +45,18 @@ USTATUS FfsOperations::extract(const UModelIndex & index, UString & name, UByteA } else return U_UNKNOWN_EXTRACT_MODE; - + return U_SUCCESS; } USTATUS FfsOperations::replace(const UModelIndex & index, UByteArray & data, const UINT8 mode) { U_UNUSED_PARAMETER(data); - + // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + if (mode == REPLACE_MODE_AS_IS) { return U_NOT_IMPLEMENTED; } @@ -64,7 +64,7 @@ USTATUS FfsOperations::replace(const UModelIndex & index, UByteArray & data, con return U_NOT_IMPLEMENTED; } - return U_UNKNOWN_REPLACE_MODE; + return U_UNKNOWN_REPLACE_MODE; } USTATUS FfsOperations::remove(const UModelIndex & index) @@ -72,10 +72,10 @@ USTATUS FfsOperations::remove(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Set remove action model->setAction(index, Actions::Remove); - + return U_SUCCESS; } @@ -84,20 +84,20 @@ USTATUS FfsOperations::rebuild(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // On insert action, set insert action for children //if (action == Actions::Insert) // for (int i = 0; i < item->childCount(); i++) // setAction(index.child(i, 0), Actions::Insert); - + // Set rebuild action model->setAction(index, Actions::Rebuild); - + // Rebuild parent, if it has no action now UModelIndex parent = index.parent(); if (parent.isValid() && model->type(parent) != Types::Root && model->action(parent) == Actions::NoAction) - rebuild(parent); + rebuild(parent); return U_SUCCESS; } diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index e915c4f..fd89720 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -1,14 +1,14 @@ /* ffsparser.cpp - -Copyright (c) 2018, 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. -*/ + + Copyright (c) 2018, 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. + */ #include "ffsparser.h" @@ -33,12 +33,12 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #ifndef QT_CORE_LIB namespace Qt { - enum GlobalColor { - red = 7, - green = 8, - cyan = 10, - yellow = 12, - }; +enum GlobalColor { + red = 7, + green = 8, + cyan = 10, + yellow = 12, +}; } #endif @@ -96,7 +96,7 @@ std::vector > FfsParser::getMessages() const { USTATUS FfsParser::parse(const UByteArray & buffer) { UModelIndex root; - + // Reset global parser state openedImage = buffer; imageBase = 0; @@ -116,7 +116,7 @@ USTATUS FfsParser::parse(const UByteArray & buffer) bgBpDigest = UByteArray(); bgProtectedRanges.clear(); bgDxeCoreIndex = UModelIndex(); - + // Parse input buffer USTATUS result = performFirstPass(buffer, root); if (result == U_SUCCESS) { @@ -127,7 +127,7 @@ USTATUS FfsParser::parse(const UByteArray & buffer) msg(usprintf("%s: not a single Volume Top File is found, the image may be corrupted", __FUNCTION__)); } } - + addInfoRecursive(root); return result; } @@ -138,21 +138,21 @@ USTATUS FfsParser::performFirstPass(const UByteArray & buffer, UModelIndex & ind if (buffer.isEmpty()) { return EFI_INVALID_PARAMETER; } - + USTATUS result; - + // Try parsing as UEFI Capsule result = parseCapsule(buffer, 0, UModelIndex(), index);; if (result != U_ITEM_NOT_FOUND) { return result; } - + // Try parsing as Intel image result = parseIntelImage(buffer, 0, UModelIndex(), index); if (result != U_ITEM_NOT_FOUND) { return result; } - + // Parse as generic image return parseGenericImage(buffer, 0, UModelIndex(), index); } @@ -161,11 +161,11 @@ USTATUS FfsParser::parseGenericImage(const UByteArray & buffer, const UINT32 loc { // Parse as generic UEFI image UString name("UEFI image"); - UString info = usprintf("Full size: %Xh (%u)", buffer.size(), buffer.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)buffer.size(), (UINT32)buffer.size()); + // Add tree item index = model->addItem(localOffset, Types::Image, Subtypes::UefiImage, name, UString(), info, UByteArray(), buffer, UByteArray(), Fixed, parent); - + // Parse the image as raw area bgProtectedRegionsBase = imageBase = model->base(parent) + localOffset; return parseRawArea(index); @@ -177,7 +177,7 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf if ((UINT32)capsule.size() < sizeof(EFI_CAPSULE_HEADER)) { return U_ITEM_NOT_FOUND; } - + UINT32 capsuleHeaderSize = 0; // Check buffer for being normal EFI capsule header if (capsule.startsWith(EFI_CAPSULE_GUID) @@ -187,7 +187,7 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf || capsule.startsWith(LENOVO2_CAPSULE_GUID)) { // Get info const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)capsule.constData(); - + // Check sanity of HeaderSize and CapsuleImageSize values if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)capsule.size() || capsuleHeader->HeaderSize > capsuleHeader->CapsuleImageSize) { @@ -202,18 +202,18 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf capsuleHeader->CapsuleImageSize)); return U_INVALID_CAPSULE; } - + capsuleHeaderSize = capsuleHeader->HeaderSize; UByteArray header = capsule.left(capsuleHeaderSize); UByteArray body = capsule.mid(capsuleHeaderSize); UString name("UEFI capsule"); UString info = UString("Capsule GUID: ") + guidToUString(capsuleHeader->CapsuleGuid, false) + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nImage size: %Xh (%u)\nFlags: %08Xh", - capsule.size(), capsule.size(), + (UINT32)capsule.size(), (UINT32)capsule.size(), capsuleHeaderSize, capsuleHeaderSize, capsuleHeader->CapsuleImageSize - capsuleHeaderSize, capsuleHeader->CapsuleImageSize - capsuleHeaderSize, capsuleHeader->Flags); - + // Add tree item index = model->addItem(localOffset, Types::Capsule, Subtypes::UefiCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent); } @@ -221,7 +221,7 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf else if (capsule.startsWith(TOSHIBA_CAPSULE_GUID)) { // Get info const TOSHIBA_CAPSULE_HEADER* capsuleHeader = (const TOSHIBA_CAPSULE_HEADER*)capsule.constData(); - + // Check sanity of HeaderSize and FullSize values if (capsuleHeader->HeaderSize == 0 || capsuleHeader->HeaderSize > (UINT32)capsule.size() || capsuleHeader->HeaderSize > capsuleHeader->FullSize) { @@ -234,18 +234,18 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf capsuleHeader->FullSize, capsuleHeader->FullSize)); return U_INVALID_CAPSULE; } - + capsuleHeaderSize = capsuleHeader->HeaderSize; UByteArray header = capsule.left(capsuleHeaderSize); UByteArray body = capsule.mid(capsuleHeaderSize); UString name("Toshiba capsule"); UString info = UString("Capsule GUID: ") + guidToUString(capsuleHeader->CapsuleGuid, false) + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nImage size: %Xh (%u)\nFlags: %08Xh", - capsule.size(), capsule.size(), + (UINT32)capsule.size(), (UINT32)capsule.size(), capsuleHeaderSize, capsuleHeaderSize, capsuleHeader->FullSize - capsuleHeaderSize, capsuleHeader->FullSize - capsuleHeaderSize, capsuleHeader->Flags); - + // Add tree item index = model->addItem(localOffset, Types::Capsule, Subtypes::ToshibaCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent); } @@ -253,15 +253,15 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf else if (capsule.startsWith(APTIO_SIGNED_CAPSULE_GUID) || capsule.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) { bool signedCapsule = capsule.startsWith(APTIO_SIGNED_CAPSULE_GUID); - + if ((UINT32)capsule.size() <= sizeof(APTIO_CAPSULE_HEADER)) { msg(usprintf("%s: AMI capsule image file is smaller than minimum size of 20h (32) bytes", __FUNCTION__)); return U_INVALID_CAPSULE; } - + // Get info const APTIO_CAPSULE_HEADER* capsuleHeader = (const APTIO_CAPSULE_HEADER*)capsule.constData(); - + // Check sanity of RomImageOffset and CapsuleImageSize values if (capsuleHeader->RomImageOffset == 0 || capsuleHeader->RomImageOffset > (UINT32)capsule.size() || capsuleHeader->RomImageOffset > capsuleHeader->CapsuleHeader.CapsuleImageSize) { @@ -275,42 +275,42 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf capsuleHeader->CapsuleHeader.CapsuleImageSize)); return U_INVALID_CAPSULE; } - + capsuleHeaderSize = capsuleHeader->RomImageOffset; UByteArray header = capsule.left(capsuleHeaderSize); UByteArray body = capsule.mid(capsuleHeaderSize); UString name("AMI Aptio capsule"); UString info = UString("Capsule GUID: ") + guidToUString(capsuleHeader->CapsuleHeader.CapsuleGuid, false) + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nImage size: %Xh (%u)\nFlags: %08Xh", - capsule.size(), capsule.size(), + (UINT32)capsule.size(), (UINT32)capsule.size(), capsuleHeaderSize, capsuleHeaderSize, capsuleHeader->CapsuleHeader.CapsuleImageSize - capsuleHeaderSize, capsuleHeader->CapsuleHeader.CapsuleImageSize - capsuleHeaderSize, capsuleHeader->CapsuleHeader.Flags); - + // Add tree item index = model->addItem(localOffset, Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + // Show message about possible Aptio signature break if (signedCapsule) { msg(usprintf("%s: Aptio capsule signature may become invalid after image modifications", __FUNCTION__), index); } } - + // Capsule present if (capsuleHeaderSize > 0) { UByteArray image = capsule.mid(capsuleHeaderSize); UModelIndex imageIndex; - + // Try parsing as Intel image USTATUS result = parseIntelImage(image, capsuleHeaderSize, index, imageIndex); if (result != U_ITEM_NOT_FOUND) { return result; } - + // Parse as generic image return parseGenericImage(image, capsuleHeaderSize, index, imageIndex); } - + return U_ITEM_NOT_FOUND; } @@ -321,19 +321,19 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l msg(usprintf("%s: input file is smaller than minimum descriptor size of %Xh (%u) bytes", __FUNCTION__, FLASH_DESCRIPTOR_SIZE, FLASH_DESCRIPTOR_SIZE)); return U_ITEM_NOT_FOUND; } - + // Store the beginning of descriptor as descriptor base address const FLASH_DESCRIPTOR_HEADER* descriptor = (const FLASH_DESCRIPTOR_HEADER*)intelImage.constData(); - + // Check descriptor signature if (descriptor->Signature != FLASH_DESCRIPTOR_SIGNATURE) { return U_ITEM_NOT_FOUND; } - + // Parse descriptor map const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)((UINT8*)descriptor + sizeof(FLASH_DESCRIPTOR_HEADER)); const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)((UINT8*)descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE); - + // Check sanity of base values if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE || descriptorMap->MasterBase == descriptorMap->RegionBase @@ -350,18 +350,18 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l msg(usprintf("%s: invalid descriptor component base %02Xh", __FUNCTION__, descriptorMap->ComponentBase)); return U_INVALID_FLASH_DESCRIPTOR; } - + const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->RegionBase); const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->ComponentBase); - + UINT8 descriptorVersion = 2; // Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ) descriptorVersion = 1; - + // Regions std::vector regions; - + // ME region REGION_INFO me; me.type = Subtypes::MeRegion; @@ -373,14 +373,14 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l me.data = intelImage.mid(me.offset, me.length); regions.push_back(me); } - + // BIOS region if (regionSection->BiosLimit) { REGION_INFO bios; bios.type = Subtypes::BiosRegion; bios.offset = calculateRegionOffset(regionSection->BiosBase); bios.length = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); - + // Check for Gigabyte specific descriptor map if (bios.length == (UINT32)intelImage.size()) { if (!me.offset) { @@ -396,19 +396,19 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l else { bios.data = intelImage.mid(bios.offset, bios.length); } - + regions.push_back(bios); } else { msg(usprintf("%s: descriptor parsing failed, BIOS region not found in descriptor", __FUNCTION__)); return U_INVALID_FLASH_DESCRIPTOR; } - + // Add all other regions for (UINT8 i = Subtypes::GbeRegion; i <= Subtypes::PttRegion; i++) { if (descriptorVersion == 1 && i == Subtypes::MicrocodeRegion) break; // Do not parse Microcode and other following regions for legacy descriptors - + const UINT16* RegionBase = ((const UINT16*)regionSection) + 2 * i; const UINT16* RegionLimit = ((const UINT16*)regionSection) + 2 * i + 1; if (*RegionLimit && !(*RegionBase == 0xFFFF && *RegionLimit == 0xFFFF)) { @@ -422,10 +422,10 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l } } } - + // Sort regions in ascending order std::sort(regions.begin(), regions.end()); - + // Check for intersections and paddings between regions REGION_INFO region; // Check intersection with the descriptor @@ -453,7 +453,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l index); return U_TRUNCATED_IMAGE; } - + // Check for intersection with previous region if (regions[i].offset < previousRegionEnd) { msg(usprintf("%s: ", __FUNCTION__) + itemSubtypeToUString(Types::Region, regions[i].type) @@ -480,25 +480,25 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l region.type = getPaddingType(region.data); regions.push_back(region); } - + // Region map is consistent - + // Intel image UString name("Intel image"); UString info = usprintf("Full size: %Xh (%u)\nFlash chips: %u\nRegions: %u\nMasters: %u\nPCH straps: %u\nPROC straps: %u", - intelImage.size(), intelImage.size(), - descriptorMap->NumberOfFlashChips + 1, // - descriptorMap->NumberOfRegions + 1, // Zero-based numbers in storage - descriptorMap->NumberOfMasters + 1, // - descriptorMap->NumberOfPchStraps, - descriptorMap->NumberOfProcStraps); - + (UINT32)intelImage.size(), (UINT32)intelImage.size(), + descriptorMap->NumberOfFlashChips + 1, // + descriptorMap->NumberOfRegions + 1, // Zero-based numbers in storage + descriptorMap->NumberOfMasters + 1, // + descriptorMap->NumberOfPchStraps, + descriptorMap->NumberOfProcStraps); + // Set image base imageBase = model->base(parent) + localOffset; - + // Add Intel image tree item index = model->addItem(localOffset, Types::Image, Subtypes::IntelImage, name, UString(), info, UByteArray(), intelImage, UByteArray(), Fixed, parent); - + // Descriptor // Get descriptor info UByteArray body = intelImage.left(FLASH_DESCRIPTOR_SIZE); @@ -510,72 +510,72 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l descriptor->ReservedVector[8], descriptor->ReservedVector[9], descriptor->ReservedVector[10], descriptor->ReservedVector[11], descriptor->ReservedVector[12], descriptor->ReservedVector[13], descriptor->ReservedVector[14], descriptor->ReservedVector[15], FLASH_DESCRIPTOR_SIZE, FLASH_DESCRIPTOR_SIZE); - + // Add offsets of actual regions for (size_t i = 0; i < regions.size(); i++) { if (regions[i].type != Subtypes::ZeroPadding && regions[i].type != Subtypes::OnePadding && regions[i].type != Subtypes::DataPadding) info += UString("\n") + itemSubtypeToUString(Types::Region, regions[i].type) + usprintf(" region offset: %Xh", regions[i].offset + localOffset); } - + // Region access settings if (descriptorVersion == 1) { const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase); info += UString("\nRegion access settings:"); info += usprintf("\nBIOS: %02Xh %02Xh ME: %02Xh %02Xh\nGbE: %02Xh %02Xh", - masterSection->BiosRead, - masterSection->BiosWrite, - masterSection->MeRead, - masterSection->MeWrite, - masterSection->GbeRead, - masterSection->GbeWrite); - + masterSection->BiosRead, + masterSection->BiosWrite, + masterSection->MeRead, + masterSection->MeWrite, + masterSection->GbeRead, + masterSection->GbeWrite); + // BIOS access table info += UString("\nBIOS access table:") - + UString("\n Read Write") - + usprintf("\nDesc %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No "); + + UString("\n Read Write") + + usprintf("\nDesc %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ", + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No "); info += UString("\nBIOS Yes Yes") - + usprintf("\nME %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No "); + + usprintf("\nME %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ", + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No "); info += usprintf("\nGbE %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No "); + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No "); info += usprintf("\nPDR %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No "); + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No "); } else if (descriptorVersion == 2) { const FLASH_DESCRIPTOR_MASTER_SECTION_V2* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION_V2*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase); info += UString("\nRegion access settings:"); info += usprintf("\nBIOS: %03Xh %03Xh ME: %03Xh %03Xh\nGbE: %03Xh %03Xh EC: %03Xh %03Xh", - masterSection->BiosRead, - masterSection->BiosWrite, - masterSection->MeRead, - masterSection->MeWrite, - masterSection->GbeRead, - masterSection->GbeWrite, - masterSection->EcRead, - masterSection->EcWrite); - + masterSection->BiosRead, + masterSection->BiosWrite, + masterSection->MeRead, + masterSection->MeWrite, + masterSection->GbeRead, + masterSection->GbeWrite, + masterSection->EcRead, + masterSection->EcWrite); + // BIOS access table info += UString("\nBIOS access table:") - + UString("\n Read Write") - + usprintf("\nDesc %s %s", - masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No "); + + UString("\n Read Write") + + usprintf("\nDesc %s %s", + masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ", + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No "); info += UString("\nBIOS Yes Yes") - + usprintf("\nME %s %s", - masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No "); + + usprintf("\nME %s %s", + masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ", + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No "); info += usprintf("\nGbE %s %s", - masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No "); + masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ", + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No "); info += usprintf("\nPDR %s %s", - masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No "); + masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ", + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No "); info += usprintf("\nEC %s %s", - masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ", - masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No "); - + masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ", + masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No "); + // Prepend descriptor version if present if (descriptorMap->DescriptorVersion != FLASH_DESCRIPTOR_VERSION_INVALID) { const FLASH_DESCRIPTOR_VERSION* version = (const FLASH_DESCRIPTOR_VERSION*)&descriptorMap->DescriptorVersion; @@ -587,7 +587,7 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l info = versionStr + "\n" + info; } } - + // VSCC table const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)((UINT8*)descriptor + ((UINT16)upperMap->VsccTableBase << 4)); info += UString("\nFlash chips in VSCC table:"); @@ -595,76 +595,76 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l for (UINT8 i = 0; i < vsscTableSize; i++) { UString jedecId = jedecIdToUString(vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1); info += usprintf("\n%02X%02X%02X (", vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1) - + jedecId - + UString(")"); + + jedecId + + UString(")"); if (jedecId == UString("Unknown")) { msg(usprintf("%s: SPI flash with unknown JEDEC ID %02X%02X%02X found in VSCC table", __FUNCTION__, vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1), index); } vsccTableEntry++; } - + // Add descriptor tree item UModelIndex regionIndex = model->addItem(localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - + // Parse regions USTATUS result = U_SUCCESS; USTATUS parseResult = U_SUCCESS; for (size_t i = 0; i < regions.size(); i++) { region = regions[i]; 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::DevExp1Region: - result = parseDevExp1Region(region.data, region.offset, index, regionIndex); - break; - case Subtypes::Bios2Region: - case Subtypes::MicrocodeRegion: - case Subtypes::EcRegion: - case Subtypes::DevExp2Region: - case Subtypes::IeRegion: - case Subtypes::Tgbe1Region: - case Subtypes::Tgbe2Region: - case Subtypes::Reserved1Region: - case Subtypes::Reserved2Region: - case Subtypes::PttRegion: - result = parseGenericRegion(region.type, region.data, region.offset, index, regionIndex); - break; - case Subtypes::ZeroPadding: - case Subtypes::OnePadding: - case Subtypes::DataPadding: { - // Add padding between regions - UByteArray padding = intelImage.mid(region.offset, region.length); - - // Get info - name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", - padding.size(), padding.size()); - - // Add tree item - regionIndex = model->addItem(region.offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - result = U_SUCCESS; + 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::DevExp1Region: + result = parseDevExp1Region(region.data, region.offset, index, regionIndex); + break; + case Subtypes::Bios2Region: + case Subtypes::MicrocodeRegion: + case Subtypes::EcRegion: + case Subtypes::DevExp2Region: + case Subtypes::IeRegion: + case Subtypes::Tgbe1Region: + case Subtypes::Tgbe2Region: + case Subtypes::Reserved1Region: + case Subtypes::Reserved2Region: + case Subtypes::PttRegion: + result = parseGenericRegion(region.type, region.data, region.offset, index, regionIndex); + break; + case Subtypes::ZeroPadding: + case Subtypes::OnePadding: + case Subtypes::DataPadding: { + // Add padding between regions + UByteArray padding = intelImage.mid(region.offset, region.length); + + // Get info + name = UString("Padding"); + info = usprintf("Full size: %Xh (%u)", + (UINT32)padding.size(), (UINT32)padding.size()); + + // Add tree item + regionIndex = model->addItem(region.offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); + result = U_SUCCESS; } break; - default: - msg(usprintf("%s: region of unknown type found", __FUNCTION__), index); - result = U_INVALID_FLASH_DESCRIPTOR; + default: + msg(usprintf("%s: region of unknown type found", __FUNCTION__), index); + result = U_INVALID_FLASH_DESCRIPTOR; } // Store the first failed result as a final result if (!parseResult && result) { parseResult = result; } } - + return parseResult; } @@ -675,21 +675,21 @@ USTATUS FfsParser::parseGbeRegion(const UByteArray & gbe, const UINT32 localOffs return U_EMPTY_REGION; if ((UINT32)gbe.size() < GBE_VERSION_OFFSET + sizeof(GBE_VERSION)) return U_INVALID_REGION; - + // Get info UString name("GbE region"); const GBE_MAC_ADDRESS* mac = (const GBE_MAC_ADDRESS*)gbe.constData(); const GBE_VERSION* version = (const GBE_VERSION*)(gbe.constData() + GBE_VERSION_OFFSET); UString info = usprintf("Full size: %Xh (%u)\nMAC: %02X:%02X:%02X:%02X:%02X:%02X\nVersion: %u.%u", - gbe.size(), gbe.size(), - mac->vendor[0], mac->vendor[1], mac->vendor[2], - mac->device[0], mac->device[1], mac->device[2], - version->major, - version->minor); - + (UINT32)gbe.size(), (UINT32)gbe.size(), + mac->vendor[0], mac->vendor[1], mac->vendor[2], + mac->device[0], mac->device[1], mac->device[2], + version->major, + version->minor); + // Add tree item index = model->addItem(localOffset, Types::Region, Subtypes::GbeRegion, name, UString(), info, UByteArray(), gbe, UByteArray(), Fixed, parent); - + return U_SUCCESS; } @@ -698,11 +698,11 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset // Check sanity if (me.isEmpty()) return U_EMPTY_REGION; - + // Get info UString name("ME region"); - UString info = usprintf("Full size: %Xh (%u)", me.size(), me.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)me.size(), (UINT32)me.size()); + // Parse region bool versionFound = true; bool emptyRegion = false; @@ -723,25 +723,25 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset versionFound = false; } } - + // Check sanity if ((UINT32)me.size() < (UINT32)versionOffset + sizeof(ME_VERSION)) return U_INVALID_REGION; - + // Add version information if (versionFound) { const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset); info += usprintf("\nVersion: %u.%u.%u.%u", - version->Major, - version->Minor, - version->Bugfix, - version->Build); + version->Major, + version->Minor, + version->Bugfix, + version->Build); } } - + // Add tree item index = model->addItem(localOffset, Types::Region, Subtypes::MeRegion, name, UString(), info, UByteArray(), me, UByteArray(), Fixed, parent); - + // Show messages if (emptyRegion) { msg(usprintf("%s: ME region is empty", __FUNCTION__), index); @@ -752,7 +752,7 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset else { meParser->parseMeRegionBody(index); } - + return U_SUCCESS; } @@ -761,19 +761,19 @@ USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffs // Check sanity if (pdr.isEmpty()) return U_EMPTY_REGION; - + // Get info UString name("PDR region"); - UString info = usprintf("Full size: %Xh (%u)", pdr.size(), pdr.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)pdr.size(), (UINT32)pdr.size()); + // Add tree item index = model->addItem(localOffset, Types::Region, Subtypes::PdrRegion, name, UString(), info, UByteArray(), pdr, UByteArray(), Fixed, parent); - + // Parse PDR region as BIOS space USTATUS result = parseRawArea(index); if (result && result != U_VOLUMES_NOT_FOUND && result != U_INVALID_VOLUME && result != U_STORES_NOT_FOUND) return result; - + return U_SUCCESS; } @@ -782,11 +782,11 @@ USTATUS FfsParser::parseDevExp1Region(const UByteArray & devExp1, const UINT32 l // Check sanity if (devExp1.isEmpty()) return U_EMPTY_REGION; - + // Get info UString name("DevExp1 region"); - UString info = usprintf("Full size: %Xh (%u)", devExp1.size(), devExp1.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)devExp1.size(), (UINT32)devExp1.size()); + bool emptyRegion = false; // Check for empty region if (devExp1.size() == devExp1.count('\xFF') || devExp1.size() == devExp1.count('\x00')) { @@ -794,10 +794,10 @@ USTATUS FfsParser::parseDevExp1Region(const UByteArray & devExp1, const UINT32 l emptyRegion = true; info += ("\nState: empty"); } - + // Add tree item index = model->addItem(localOffset, Types::Region, Subtypes::DevExp1Region, name, UString(), info, UByteArray(), devExp1, UByteArray(), Fixed, parent); - + if (!emptyRegion) { meParser->parseMeRegionBody(index); } @@ -809,14 +809,14 @@ USTATUS FfsParser::parseGenericRegion(const UINT8 subtype, const UByteArray & re // Check sanity if (region.isEmpty()) return U_EMPTY_REGION; - + // Get info UString name = itemSubtypeToUString(Types::Region, subtype) + UString(" region"); - UString info = usprintf("Full size: %Xh (%u)", region.size(), region.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)region.size(), (UINT32)region.size()); + // Add tree item index = model->addItem(localOffset, Types::Region, subtype, name, UString(), info, UByteArray(), region, UByteArray(), Fixed, parent); - + return U_SUCCESS; } @@ -825,14 +825,14 @@ USTATUS FfsParser::parseBiosRegion(const UByteArray & bios, const UINT32 localOf // Sanity check if (bios.isEmpty()) return U_EMPTY_REGION; - + // Get info UString name("BIOS region"); - UString info = usprintf("Full size: %Xh (%u)", bios.size(), bios.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)bios.size(), (UINT32)bios.size()); + // Add tree item index = model->addItem(localOffset, Types::Region, Subtypes::BiosRegion, name, UString(), info, UByteArray(), bios, UByteArray(), Fixed, parent); - + return parseRawArea(index); } @@ -841,84 +841,84 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Get item data UByteArray data = model->body(index); UINT32 headerSize = (UINT32)model->header(index).size(); - + USTATUS result; UString name; UString info; - + // Search for the first item UINT8 prevItemType = 0; UINT32 prevItemOffset = 0; UINT32 prevItemSize = 0; UINT32 prevItemAltSize = 0; - + result = findNextRawAreaItem(index, 0, prevItemType, prevItemOffset, prevItemSize, prevItemAltSize); if (result) { // No need to parse further return U_SUCCESS; } - + // Set base of protected regions to be the first volume if (model->type(index) == Types::Region && model->subtype(index) == Subtypes::BiosRegion) { bgProtectedRegionsBase = (UINT64)model->base(index) + prevItemOffset; } - + // First item is not at the beginning of this raw area if (prevItemOffset > 0) { // Get info UByteArray padding = data.left(prevItemOffset); name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item model->addItem(headerSize, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + // Search for and parse all items UINT8 itemType = prevItemType; UINT32 itemOffset = prevItemOffset; UINT32 itemSize = prevItemSize; UINT32 itemAltSize = prevItemAltSize; - + while (!result) { // Padding between items if (itemOffset > prevItemOffset + prevItemSize) { UINT32 paddingOffset = prevItemOffset + prevItemSize; UINT32 paddingSize = itemOffset - paddingOffset; UByteArray padding = data.mid(paddingOffset, paddingSize); - + // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item model->addItem(headerSize + paddingOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + // Check that item is fully present in input if (itemSize > (UINT32)data.size() || itemOffset + itemSize > (UINT32)data.size()) { // Mark the rest as padding and finish parsing UByteArray padding = data.mid(itemOffset); - + // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item UModelIndex paddingIndex = model->addItem(headerSize + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); msg(usprintf("%s: one of volumes inside overlaps the end of data", __FUNCTION__), paddingIndex); - + // Update variables prevItemOffset = itemOffset; prevItemSize = (UINT32)padding.size(); break; } - + // Parse current volume header if (itemType == Types::Volume) { UModelIndex volumeIndex; @@ -930,8 +930,8 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index) // Show messages if (itemSize != itemAltSize) msg(usprintf("%s: volume size stored in header %Xh differs from calculated using block map %Xh", __FUNCTION__, - itemSize, itemAltSize), - volumeIndex); + itemSize, itemAltSize), + volumeIndex); } } else if (itemType == Types::Microcode) { @@ -944,14 +944,14 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index) } else if (itemType == Types::BpdtStore) { UByteArray bpdtStore = data.mid(itemOffset, itemSize); - + // Get info name = UString("BPDT region"); - info = usprintf("Full size: %Xh (%u)", bpdtStore.size(), bpdtStore.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)bpdtStore.size(), (UINT32)bpdtStore.size()); + // Add tree item UModelIndex bpdtIndex = model->addItem(headerSize + itemOffset, Types::BpdtStore, 0, name, UString(), info, UByteArray(), bpdtStore, UByteArray(), Fixed, index); - + // Parse BPDT region UModelIndex bpdtPtIndex; result = parseBpdtRegion(bpdtStore, 0, 0, bpdtIndex, bpdtPtIndex); @@ -962,55 +962,55 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index) else { return U_UNKNOWN_ITEM_TYPE; } - + // Go to next item prevItemOffset = itemOffset; prevItemSize = itemSize; prevItemType = itemType; result = findNextRawAreaItem(index, itemOffset + prevItemSize, itemType, itemOffset, itemSize, itemAltSize); - + // Silence value not used after assignment warning (void)prevItemType; } - + // Padding at the end of RAW area itemOffset = prevItemOffset + prevItemSize; if ((UINT32)data.size() > itemOffset) { UByteArray padding = data.mid(itemOffset); - + // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item model->addItem(headerSize + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + // Parse bodies for (int i = 0; i < model->rowCount(index); i++) { UModelIndex current = index.model()->index(i, 0, index); - + switch (model->type(current)) { - case Types::Volume: - parseVolumeBody(current); - break; - case Types::Microcode: - // Parsing already done - break; - case Types::BpdtStore: - // Parsing already done - break; - case Types::BpdtPartition: - // Parsing already done - break; - case Types::Padding: - // No parsing required - break; - default: - return U_UNKNOWN_ITEM_TYPE; + case Types::Volume: + parseVolumeBody(current); + break; + case Types::Microcode: + // Parsing already done + break; + case Types::BpdtStore: + // Parsing already done + break; + case Types::BpdtPartition: + // Parsing already done + break; + case Types::Padding: + // No parsing required + break; + default: + return U_UNKNOWN_ITEM_TYPE; } } - + return U_SUCCESS; } @@ -1019,16 +1019,16 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc // Sanity check if (volume.isEmpty()) return U_INVALID_PARAMETER; - + // Check that there is space for the volume header if ((UINT32)volume.size() < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { - msg(usprintf("%s: input volume size %Xh (%u) is smaller than volume header size 40h (64)", __FUNCTION__, volume.size(), volume.size())); + msg(usprintf("%s: input volume size %Xh (%u) is smaller than volume header size 40h (64)", __FUNCTION__, (UINT32)volume.size(), (UINT32)volume.size())); return U_INVALID_VOLUME; } - + // Populate volume header const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(volume.constData()); - + // Check sanity of HeaderLength value if ((UINT32)ALIGN8(volumeHeader->HeaderLength) > (UINT32)volume.size()) { msg(usprintf("%s: volume header overlaps the end of data", __FUNCTION__)); @@ -1040,7 +1040,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc msg(usprintf("%s: extended volume header overlaps the end of data", __FUNCTION__)); return U_INVALID_VOLUME; } - + // Calculate volume header size UINT32 headerSize; EFI_GUID extendedHeaderGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0 }}; @@ -1054,16 +1054,16 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc else { headerSize = volumeHeader->HeaderLength; } - + // Extended header end can be unaligned headerSize = ALIGN8(headerSize); - + // Check for volume structure to be known bool isUnknown = true; bool isNvramVolume = false; bool isMicrocodeVolume = false; UINT8 ffsVersion = 0; - + // Check for FFS v2 volume UByteArray guid = UByteArray((const char*)&volumeHeader->FileSystemGuid, sizeof(EFI_GUID)); if (std::find(FFSv2Volumes.begin(), FFSv2Volumes.end(), guid) != FFSv2Volumes.end()) { @@ -1086,7 +1086,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc isMicrocodeVolume = true; headerSize = EFI_APPLE_MICROCODE_VOLUME_HEADER_SIZE; } - + // Check volume revision and alignment bool msgAlignmentBitsSet = false; bool msgUnaligned = false; @@ -1114,11 +1114,11 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc else { msgUnknownRevision = true; } - + // Check attributes // Determine value of empty byte UINT8 emptyByte = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; - + // Check for AppleCRC32 and UsedSpace in ZeroVector bool hasAppleCrc32 = false; UINT32 volumeSize = (UINT32)volume.size(); @@ -1131,7 +1131,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc hasAppleCrc32 = true; } } - + // Check header checksum by recalculating it bool msgInvalidChecksum = false; UByteArray tempHeader((const char*)volumeHeader, volumeHeader->HeaderLength); @@ -1139,41 +1139,41 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc UINT16 calculated = calculateChecksum16((const UINT16*)tempHeader.constData(), volumeHeader->HeaderLength); if (volumeHeader->Checksum != calculated) msgInvalidChecksum = true; - + // Get info UByteArray header = volume.left(headerSize); UByteArray body = volume.mid(headerSize); UString name = guidToUString(volumeHeader->FileSystemGuid); UString info = usprintf("ZeroVector:\n%02X %02X %02X %02X %02X %02X %02X %02X\n" - "%02X %02X %02X %02X %02X %02X %02X %02X\nSignature: _FVH\nFileSystem GUID: ", - volumeHeader->ZeroVector[0], volumeHeader->ZeroVector[1], volumeHeader->ZeroVector[2], volumeHeader->ZeroVector[3], - volumeHeader->ZeroVector[4], volumeHeader->ZeroVector[5], volumeHeader->ZeroVector[6], volumeHeader->ZeroVector[7], - volumeHeader->ZeroVector[8], volumeHeader->ZeroVector[9], volumeHeader->ZeroVector[10], volumeHeader->ZeroVector[11], - volumeHeader->ZeroVector[12], volumeHeader->ZeroVector[13], volumeHeader->ZeroVector[14], volumeHeader->ZeroVector[15]) - + guidToUString(volumeHeader->FileSystemGuid, false) \ - + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nRevision: %u\nAttributes: %08Xh\nErase polarity: %u\nChecksum: %04Xh", - volumeSize, volumeSize, - headerSize, headerSize, - volumeSize - headerSize, volumeSize - headerSize, - volumeHeader->Revision, - volumeHeader->Attributes, - (emptyByte ? 1 : 0), - volumeHeader->Checksum) + - (msgInvalidChecksum ? usprintf(", invalid, should be %04Xh", calculated) : UString(", valid")); - + "%02X %02X %02X %02X %02X %02X %02X %02X\nSignature: _FVH\nFileSystem GUID: ", + volumeHeader->ZeroVector[0], volumeHeader->ZeroVector[1], volumeHeader->ZeroVector[2], volumeHeader->ZeroVector[3], + volumeHeader->ZeroVector[4], volumeHeader->ZeroVector[5], volumeHeader->ZeroVector[6], volumeHeader->ZeroVector[7], + volumeHeader->ZeroVector[8], volumeHeader->ZeroVector[9], volumeHeader->ZeroVector[10], volumeHeader->ZeroVector[11], + volumeHeader->ZeroVector[12], volumeHeader->ZeroVector[13], volumeHeader->ZeroVector[14], volumeHeader->ZeroVector[15]) + + guidToUString(volumeHeader->FileSystemGuid, false) \ + + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nRevision: %u\nAttributes: %08Xh\nErase polarity: %u\nChecksum: %04Xh", + volumeSize, volumeSize, + headerSize, headerSize, + volumeSize - headerSize, volumeSize - headerSize, + volumeHeader->Revision, + volumeHeader->Attributes, + (emptyByte ? 1 : 0), + volumeHeader->Checksum) + + (msgInvalidChecksum ? usprintf(", invalid, should be %04Xh", calculated) : UString(", valid")); + // Extended header present if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { const EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (const EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset); info += usprintf("\nExtended header size: %Xh (%u)\nVolume GUID: ", - extendedHeader->ExtHeaderSize, extendedHeader->ExtHeaderSize) + guidToUString(extendedHeader->FvName, false); + extendedHeader->ExtHeaderSize, extendedHeader->ExtHeaderSize) + guidToUString(extendedHeader->FvName, false); name = guidToUString(extendedHeader->FvName); // Replace FFS GUID with volume GUID } - + // Add text UString text; if (hasAppleCrc32) text += UString("AppleCRC32 "); - + // Add tree item UINT8 subtype = Subtypes::UnknownVolume; if (!isUnknown) { @@ -1187,7 +1187,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc subtype = Subtypes::MicrocodeVolume; } index = model->addItem(localOffset, Types::Volume, subtype, name, text, info, header, body, UByteArray(), Movable, parent); - + // Set parsing data for created volume VOLUME_PARSING_DATA pdata = {}; pdata.emptyByte = emptyByte; @@ -1201,7 +1201,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc pdata.usedSpace = usedSpace; pdata.isWeakAligned = (volumeHeader->Revision > 1 && (volumeHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT)); model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); - + // Show messages if (isUnknown) msg(usprintf("%s: unknown file system ", __FUNCTION__) + guidToUString(volumeHeader->FileSystemGuid), index); @@ -1213,7 +1213,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc msg(usprintf("%s: unaligned volume", __FUNCTION__), index); if (msgUnknownRevision) msg(usprintf("%s: unknown volume revision %u", __FUNCTION__, volumeHeader->Revision), index); - + return U_SUCCESS; } @@ -1230,7 +1230,7 @@ BOOLEAN FfsParser::microcodeHeaderValid(const INTEL_MICROCODE_HEADER* ucodeHeade if (!reservedBytesValid) { return FALSE; } - + // Check CpuFlags reserved bytes to be zero for (UINT32 i = 0; i < sizeof(ucodeHeader->ProcessorFlagsReserved); i++) { if (ucodeHeader->ProcessorFlagsReserved[i] != 0x00) { @@ -1241,19 +1241,19 @@ BOOLEAN FfsParser::microcodeHeaderValid(const INTEL_MICROCODE_HEADER* ucodeHeade if (!reservedBytesValid) { return FALSE; } - + // Check data size to be multiple of 4 and less than 0x1000000 if (ucodeHeader->DataSize % 4 != 0 || ucodeHeader->DataSize > 0xFFFFFF) { return FALSE; } - + // Check TotalSize to be greater or equal than DataSize and less than 0x1000000 if (ucodeHeader->TotalSize < ucodeHeader->DataSize || ucodeHeader->TotalSize > 0xFFFFFF) { return FALSE; } - + // Check date to be sane // Check day to be in 0x01-0x09, 0x10-0x19, 0x20-0x29, 0x30-0x31 if (ucodeHeader->DateDay < 0x01 || @@ -1287,7 +1287,7 @@ BOOLEAN FfsParser::microcodeHeaderValid(const INTEL_MICROCODE_HEADER* ucodeHeade if (ucodeHeader->LoaderRevision != 1) { return FALSE; } - + return TRUE; } @@ -1295,10 +1295,10 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l { UByteArray data = model->body(index); UINT32 dataSize = (UINT32)data.size(); - + if (dataSize < sizeof(UINT32)) return U_STORES_NOT_FOUND; - + UINT32 offset = localOffset; for (; offset < dataSize - sizeof(UINT32); offset++) { const UINT32* currentPos = (const UINT32*)(data.constData() + offset); @@ -1308,17 +1308,17 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l if (restSize < sizeof(INTEL_MICROCODE_HEADER)) { continue; } - + // Check microcode header candidate const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos; if (FALSE == microcodeHeaderValid(ucodeHeader)) { continue; } - + // Check size candidate if (ucodeHeader->TotalSize == 0) continue; - + // All checks passed, microcode found nextItemType = Types::Microcode; nextItemSize = ucodeHeader->TotalSize; @@ -1329,7 +1329,7 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l else if (readUnaligned(currentPos) == EFI_FV_SIGNATURE) { if (offset < EFI_FV_SIGNATURE_OFFSET) continue; - + const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(data.constData() + offset - EFI_FV_SIGNATURE_OFFSET); if (volumeHeader->FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY) || volumeHeader->FvLength >= 0xFFFFFFFFUL) { continue; @@ -1337,19 +1337,19 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l if (volumeHeader->Revision != 1 && volumeHeader->Revision != 2) { continue; } - + // Calculate alternative volume size using its BlockMap nextItemAlternativeSize = 0; const EFI_FV_BLOCK_MAP_ENTRY* entry = (const EFI_FV_BLOCK_MAP_ENTRY*)(data.constData() + offset - EFI_FV_SIGNATURE_OFFSET + sizeof(EFI_FIRMWARE_VOLUME_HEADER)); while (entry->NumBlocks != 0 && entry->Length != 0) { if ((void*)entry >= data.constData() + data.size()) { - continue; + continue; } - + nextItemAlternativeSize += entry->NumBlocks * entry->Length; entry += 1; } - + // All checks passed, volume found nextItemType = Types::Volume; nextItemSize = (UINT32)volumeHeader->FvLength; @@ -1360,18 +1360,18 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l // Check data size if (restSize < sizeof(BPDT_HEADER)) continue; - + const BPDT_HEADER *bpdtHeader = (const BPDT_HEADER *)currentPos; // Check version if (bpdtHeader->HeaderVersion != BPDT_HEADER_VERSION_1) // IFWI 2.0 only for now continue; - + UINT32 ptBodySize = bpdtHeader->NumEntries * sizeof(BPDT_ENTRY); UINT32 ptSize = sizeof(BPDT_HEADER) + ptBodySize; // Check data size again if (restSize < ptSize) continue; - + UINT32 sizeCandidate = 0; // Parse partition table const BPDT_ENTRY* firstPtEntry = (const BPDT_ENTRY*)((const UINT8*)bpdtHeader + sizeof(BPDT_HEADER)); @@ -1383,15 +1383,15 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l && ptEntry->Offset != 0xFFFFFFFF && ptEntry->Size != 0 && sizeCandidate < ptEntry->Offset + ptEntry->Size) { - sizeCandidate = ptEntry->Offset + ptEntry->Size; + sizeCandidate = ptEntry->Offset + ptEntry->Size; } } - + // Check size candidate if (sizeCandidate == 0) continue; - - // All checks passed, BPDT found + + // All checks passed, BPDT found nextItemType = Types::BpdtStore; nextItemSize = sizeCandidate; nextItemAlternativeSize = sizeCandidate; @@ -1399,12 +1399,12 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l break; } } - + // No more stores found if (offset >= dataSize - sizeof(UINT32)) { return U_STORES_NOT_FOUND; } - + return U_SUCCESS; } @@ -1413,14 +1413,14 @@ USTATUS FfsParser::parseVolumeNonUefiData(const UByteArray & data, const UINT32 // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Get info - UString info = usprintf("Full size: %Xh (%u)", data.size(), data.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)data.size(), (UINT32)data.size()); + // Add padding tree item UModelIndex paddingIndex = model->addItem(localOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), data, UByteArray(), Fixed, index); msg(usprintf("%s: non-UEFI data found in volume's free space", __FUNCTION__), paddingIndex); - + // Parse contents as RAW area return parseRawArea(paddingIndex); } @@ -1431,21 +1431,21 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index) if (!index.isValid()) { return U_INVALID_PARAMETER; } - + // Get volume header size and body UByteArray volumeBody = model->body(index); UINT32 volumeHeaderSize = (UINT32)model->header(index).size(); - + // Parse VSS NVRAM volumes with a dedicated function if (model->subtype(index) == Subtypes::NvramVolume) { return nvramParser->parseNvramVolumeBody(index); } - + // Parse Microcode volume with a dedicated function if (model->subtype(index) == Subtypes::MicrocodeVolume) { return parseMicrocodeVolumeBody(index); } - + // Get required values from parsing data UINT8 emptyByte = 0xFF; UINT8 ffsVersion = 2; @@ -1457,25 +1457,25 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index) ffsVersion = pdata->ffsVersion; usedSpace = pdata->usedSpace; } - + // Check for unknown FFS version if (ffsVersion != 2 && ffsVersion != 3) { msg(usprintf("%s: unknown FFS version %d", __FUNCTION__, ffsVersion), index); return U_SUCCESS; } - + // Search for and parse all files UINT32 volumeBodySize = (UINT32)volumeBody.size(); UINT32 fileOffset = 0; - + while (fileOffset < volumeBodySize) { UINT32 fileSize = getFileSize(volumeBody, fileOffset, ffsVersion); - + if (fileSize == 0) { msg(usprintf("%s: file header parsing failed with invalid size", __FUNCTION__), index); break; // Exit from parsing loop } - + // Check that we are at the empty space UByteArray header = volumeBody.mid(fileOffset, (int)std::min(sizeof(EFI_FFS_FILE_HEADER), (size_t)volumeBodySize - fileOffset)); if (header.count(emptyByte) == header.size()) { //Empty space @@ -1489,7 +1489,7 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index) model->setText(index, model->text(index) + "UsedSpace "); } } - + // Check free space to be actually free UByteArray freeSpace = volumeBody.mid(fileOffset); if (freeSpace.count(emptyByte) != freeSpace.size()) { @@ -1502,109 +1502,109 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index) break; // Exit from parsing loop } } - + // Align found index to file alignment // It must be possible because minimum 16 bytes of empty were found before if (i != ALIGN8(i)) { i = ALIGN8(i) - 8; } - + // Add all bytes before as free space if (i > 0) { UByteArray free = freeSpace.left(i); - + // Get info - UString info = usprintf("Full size: %Xh (%u)", free.size(), free.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)free.size(), (UINT32)free.size()); + // Add free space item model->addItem(volumeHeaderSize + fileOffset, Types::FreeSpace, 0, UString("Volume free space"), UString(), info, UByteArray(), free, UByteArray(), Movable, index); } - + // Parse non-UEFI data parseVolumeNonUefiData(freeSpace.mid(i), volumeHeaderSize + fileOffset + i, index); } else { // Get info - UString info = usprintf("Full size: %Xh (%u)", freeSpace.size(), freeSpace.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)freeSpace.size(), (UINT32)freeSpace.size()); + // Add free space item model->addItem(volumeHeaderSize + fileOffset, Types::FreeSpace, 0, UString("Volume free space"), UString(), info, UByteArray(), freeSpace, UByteArray(), Movable, index); } - + break; // Exit from parsing loop } - + // We aren't at the end of empty space // Check that the remaining space can still have a file in it if (volumeBodySize - fileOffset < sizeof(EFI_FFS_FILE_HEADER) || // Remaining space is smaller than the smallest possible file volumeBodySize - fileOffset < fileSize) { // Remaining space is smaller than non-empty file size // Parse non-UEFI data parseVolumeNonUefiData(volumeBody.mid(fileOffset), volumeHeaderSize + fileOffset, index); - + break; // Exit from parsing loop } - + // Parse current file's header UModelIndex fileIndex; USTATUS result = parseFileHeader(volumeBody.mid(fileOffset, fileSize), volumeHeaderSize + fileOffset, index, fileIndex); if (result) { msg(usprintf("%s: file header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index); } - + // Move to next file fileOffset += fileSize; // TODO: check that alignment bytes are all of erase polarity bit, warn if not so fileOffset = ALIGN8(fileOffset); } - + // Check for duplicate GUIDs for (int i = 0; i < model->rowCount(index); i++) { UModelIndex current = index.model()->index(i, 0, index); - + // Skip non-file entries and pad files if (model->type(current) != Types::File || model->subtype(current) == EFI_FV_FILETYPE_PAD) { continue; } - + // Get current file GUID UByteArray currentGuid(model->header(current).constData(), sizeof(EFI_GUID)); - + // Check files after current for having an equal GUID for (int j = i + 1; j < model->rowCount(index); j++) { UModelIndex another = index.model()->index(j, 0, index); - + // Skip non-file entries if (model->type(another) != Types::File) { continue; } - + // Get another file GUID UByteArray anotherGuid(model->header(another).constData(), sizeof(EFI_GUID)); - + // Check GUIDs for being equal if (currentGuid == anotherGuid) { msg(usprintf("%s: file with duplicate GUID ", __FUNCTION__) + guidToUString(readUnaligned((EFI_GUID*)(anotherGuid.data()))), another); } } } - + // Parse bodies for (int i = 0; i < model->rowCount(index); i++) { UModelIndex current = index.model()->index(i, 0, index); - + switch (model->type(current)) { - case Types::File: - parseFileBody(current); - break; - case Types::Padding: - case Types::FreeSpace: - // No parsing required - break; - default: - return U_UNKNOWN_ITEM_TYPE; + case Types::File: + parseFileBody(current); + break; + case Types::Padding: + case Types::FreeSpace: + // No parsing required + break; + default: + return U_UNKNOWN_ITEM_TYPE; } } - + return U_SUCCESS; } @@ -1613,9 +1613,9 @@ UINT32 FfsParser::getFileSize(const UByteArray & volume, const UINT32 fileOffset if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER)) { return 0; } - + const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)(volume.constData() + fileOffset); - + if (ffsVersion == 2) { return uint24ToUint32(fileHeader->Size); } @@ -1624,14 +1624,14 @@ UINT32 FfsParser::getFileSize(const UByteArray & volume, const UINT32 fileOffset if ((UINT32)volume.size() < fileOffset + sizeof(EFI_FFS_FILE_HEADER2)) { return 0; } - + const EFI_FFS_FILE_HEADER2* fileHeader2 = (const EFI_FFS_FILE_HEADER2*)(volume.constData() + fileOffset); return (UINT32) fileHeader2->ExtendedSize; } - + return uint24ToUint32(fileHeader->Size); } - + return 0; } @@ -1644,7 +1644,7 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER)) { return U_INVALID_FILE; } - + // Obtain required information from parent volume UINT8 ffsVersion = 2; bool isWeakAligned = false; @@ -1659,7 +1659,7 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf volumeRevision = pdata->revision; isWeakAligned = pdata->isWeakAligned; } - + // Get file header UByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER)); EFI_FFS_FILE_HEADER* tempFileHeader = (EFI_FFS_FILE_HEADER*)header.data(); @@ -1669,28 +1669,28 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf header = file.left(sizeof(EFI_FFS_FILE_HEADER2)); } const EFI_FFS_FILE_HEADER* fileHeader = (const EFI_FFS_FILE_HEADER*)header.constData(); - + // Check file alignment bool msgUnalignedFile = false; UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3]; if (volumeRevision > 1 && (fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2)) { alignmentPower = ffsAlignment2Table[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3]; } - + UINT32 alignment = (UINT32)(1UL << alignmentPower); if ((localOffset + header.size()) % alignment) { msgUnalignedFile = true; } - + // Check file alignment against volume alignment bool msgFileAlignmentIsGreaterThanVolumeAlignment = false; if (!isWeakAligned && volumeAlignment < alignment) { msgFileAlignmentIsGreaterThanVolumeAlignment = true; } - + // Get file body UByteArray body = file.mid(header.size()); - + // Check for file tail presence UByteArray tail; bool msgInvalidTailValue = false; @@ -1699,19 +1699,19 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf UINT16 tailValue = *(UINT16*)body.right(sizeof(UINT16)).constData(); if (fileHeader->IntegrityCheck.TailReference != (UINT16)~tailValue) msgInvalidTailValue = true; - + // Get tail and remove it from file body tail = body.right(sizeof(UINT16)); body = body.left(body.size() - sizeof(UINT16)); } - + // Check header checksum UINT8 calculatedHeader = 0x100 - (calculateSum8((const UINT8*)header.constData(), (UINT32)header.size()) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State); bool msgInvalidHeaderChecksum = false; if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader) { msgInvalidHeaderChecksum = true; } - + // Check data checksum // Data checksum must be calculated bool msgInvalidDataChecksum = false; @@ -1726,17 +1726,17 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf else { calculatedData = FFS_FIXED_CHECKSUM2; } - + if (fileHeader->IntegrityCheck.Checksum.File != calculatedData) { msgInvalidDataChecksum = true; } - + // Check file type bool msgUnknownType = false; if (fileHeader->Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE && fileHeader->Type != EFI_FV_FILETYPE_PAD) { msgUnknownType = true; }; - + // Get info UString name; UString info; @@ -1745,19 +1745,19 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf } else { name = UString("Pad-file"); } - + info = UString("File GUID: ") + guidToUString(fileHeader->Name, false) + - usprintf("\nType: %02Xh\nAttributes: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)\nState: %02Xh", - fileHeader->Type, - fileHeader->Attributes, - header.size() + body.size() + tail.size(), header.size() + body.size() + tail.size(), - header.size(), header.size(), - body.size(), body.size(), - tail.size(), tail.size(), - fileHeader->State) + - usprintf("\nHeader checksum: %02Xh", fileHeader->IntegrityCheck.Checksum.Header) + (msgInvalidHeaderChecksum ? usprintf(", invalid, should be %02Xh", calculatedHeader) : UString(", valid")) + - usprintf("\nData checksum: %02Xh", fileHeader->IntegrityCheck.Checksum.File) + (msgInvalidDataChecksum ? usprintf(", invalid, should be %02Xh", calculatedData) : UString(", valid")); - + usprintf("\nType: %02Xh\nAttributes: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)\nState: %02Xh", + fileHeader->Type, + fileHeader->Attributes, + (UINT32)(header.size() + body.size() + tail.size()), (UINT32)(header.size() + body.size() + tail.size()), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + (UINT32)tail.size(), (UINT32)tail.size(), + fileHeader->State) + + usprintf("\nHeader checksum: %02Xh", fileHeader->IntegrityCheck.Checksum.Header) + (msgInvalidHeaderChecksum ? usprintf(", invalid, should be %02Xh", calculatedHeader) : UString(", valid")) + + usprintf("\nData checksum: %02Xh", fileHeader->IntegrityCheck.Checksum.File) + (msgInvalidDataChecksum ? usprintf(", invalid, should be %02Xh", calculatedData) : UString(", valid")); + UString text; bool isVtf = false; bool isDxeCore = false; @@ -1776,29 +1776,29 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf // This information may be used to determine DXE volume offset for old AMI or post-IBB protected ranges isDxeCore = true; } - + // Construct fixed state ItemFixedState fixed = (ItemFixedState)((fileHeader->Attributes & FFS_ATTRIB_FIXED) != 0); - + // Add tree item index = model->addItem(localOffset, Types::File, fileHeader->Type, name, text, info, header, body, tail, fixed, parent); - + // Set parsing data for created file FILE_PARSING_DATA pdata = {}; pdata.emptyByte = (fileHeader->State & EFI_FILE_ERASE_POLARITY) ? 0xFF : 0x00; pdata.guid = fileHeader->Name; model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); - + // Override lastVtf index, if needed if (isVtf) { lastVtf = index; } - + // Override first DXE core index, if needed if (isDxeCore && !bgDxeCoreIndex.isValid()) { bgDxeCoreIndex = index; } - + // Show messages if (msgUnalignedFile) msg(usprintf("%s: unaligned file", __FUNCTION__), index); @@ -1812,7 +1812,7 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf msg(usprintf("%s: invalid tail value %04Xh", __FUNCTION__, *(const UINT16*)tail.constData()), index); if (msgUnknownType) msg(usprintf("%s: unknown file type %02Xh", __FUNCTION__, fileHeader->Type), index); - + return U_SUCCESS; } @@ -1822,7 +1822,7 @@ UINT32 FfsParser::getSectionSize(const UByteArray & file, const UINT32 sectionOf return 0; } const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(file.constData() + sectionOffset); - + if (ffsVersion == 2) { return uint24ToUint32(sectionHeader->Size); } @@ -1835,10 +1835,10 @@ UINT32 FfsParser::getSectionSize(const UByteArray & file, const UINT32 sectionOf const EFI_COMMON_SECTION_HEADER2* sectionHeader2 = (const EFI_COMMON_SECTION_HEADER2*)(file.constData() + sectionOffset); return sectionHeader2->ExtendedSize; } - + return size; } - + return 0; } @@ -1847,19 +1847,19 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Do not parse non-file bodies if (model->type(index) != Types::File) return U_SUCCESS; - + // Parse pad-file body if (model->subtype(index) == EFI_FV_FILETYPE_PAD) return parsePadFileBody(index); - + // Parse raw files as raw areas if (model->subtype(index) == EFI_FV_FILETYPE_RAW || model->subtype(index) == EFI_FV_FILETYPE_ALL) { UByteArray fileGuid = UByteArray(model->header(index).constData(), sizeof(EFI_GUID)); - + // Parse NVAR store if (fileGuid == NVRAM_NVAR_STORE_FILE_GUID) { model->setText(index, UString("NVAR store")); @@ -1877,10 +1877,10 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index) else if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX) { return parseVendorHashFile(fileGuid, index); } - + return parseRawArea(index); } - + // Parse sections return parseSections(model->body(index), index, true); } @@ -1890,10 +1890,10 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Check if all bytes of the file are empty UByteArray body = model->body(index); - + // Obtain required information from parent file UINT8 emptyByte = 0xFF; UModelIndex parentFileIndex = model->findParentOfType(index, Types::File); @@ -1902,11 +1902,11 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index) const FILE_PARSING_DATA* pdata = (const FILE_PARSING_DATA*)data.constData(); emptyByte = pdata->emptyByte; } - + // Check if the while PAD file is empty if (body.size() == body.count(emptyByte)) return U_SUCCESS; - + // Search for the first non-empty byte UINT32 nonEmptyByteOffset; UINT32 size = (UINT32)body.size(); @@ -1915,41 +1915,41 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index) if (*current++ != emptyByte) break; } - + // Add all bytes before as free space... UINT32 headerSize = (UINT32)model->header(index).size(); if (nonEmptyByteOffset >= 8) { // Align free space to 8 bytes boundary if (nonEmptyByteOffset != ALIGN8(nonEmptyByteOffset)) nonEmptyByteOffset = ALIGN8(nonEmptyByteOffset) - 8; - + UByteArray free = body.left(nonEmptyByteOffset); - + // Get info - UString info = usprintf("Full size: %Xh (%u)", free.size(), free.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)free.size(), (UINT32)free.size()); + // Add tree item model->addItem(headerSize, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), free, UByteArray(), Movable, index); } else { nonEmptyByteOffset = 0; } - + // ... and all bytes after as a padding UByteArray padding = body.mid(nonEmptyByteOffset); - + // Get info - UString info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item UModelIndex dataIndex = model->addItem(headerSize + nonEmptyByteOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - + // Show message msg(usprintf("%s: non-UEFI data found in pad-file", __FUNCTION__), dataIndex); - + // Rename the file model->setName(index, UString("Non-empty pad-file")); - + // Parse contents as RAW area return parseRawArea(dataIndex); } @@ -1959,13 +1959,13 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Search for and parse all sections UINT32 bodySize = (UINT32)sections.size(); UINT32 headerSize = (UINT32)model->header(index).size(); UINT32 sectionOffset = 0; USTATUS result = U_SUCCESS; - + // Obtain required information from parent volume UINT8 ffsVersion = 2; UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume); @@ -1974,13 +1974,13 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); ffsVersion = pdata->ffsVersion; } - + // Iterate over sections UINT32 sectionSize = 0; while (sectionOffset < bodySize) { // Get section size sectionSize = getSectionSize(sections, sectionOffset, ffsVersion); - + // Check section size to be sane if (sectionSize < sizeof(EFI_COMMON_SECTION_HEADER) || sectionSize > (bodySize - sectionOffset)) { @@ -1988,16 +1988,16 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex if (insertIntoTree) { // Add padding to fill the rest of sections UByteArray padding = sections.mid(sectionOffset); - + // Get info - UString info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item UModelIndex dataIndex = model->addItem(headerSize + sectionOffset, Types::Padding, Subtypes::DataPadding, UString("Non-UEFI data"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); - + // Show message msg(usprintf("%s: non-UEFI data found in sections area", __FUNCTION__), dataIndex); - + // Exit from parsing loop break; } @@ -2006,7 +2006,7 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex return U_INVALID_SECTION; } } - + // Parse section header UModelIndex sectionIndex; result = parseSectionHeader(sections.mid(sectionOffset, sectionSize), headerSize + sectionOffset, index, sectionIndex, insertIntoTree); @@ -2016,13 +2016,13 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex else return U_INVALID_SECTION; } - + // Move to next section sectionOffset += sectionSize; // TODO: verify that alignment bytes are actually zero as per PI spec sectionOffset = ALIGN4(sectionOffset); } - + #if 0 // Do not enable this in production for now, as it needs further investigation. // The PI spec requires sections to be aligned by 4 byte boundary with bytes that are all exactly zeroes // Some images interpret "must be aligned by 4" as "every section needs to be padded for sectionSize to be divisible by 4". @@ -2046,19 +2046,19 @@ USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex // Parse bodies, will be skipped if insertIntoTree is not required for (int i = 0; i < model->rowCount(index); i++) { UModelIndex current = index.model()->index(i, 0, index); - + switch (model->type(current)) { - case Types::Section: - parseSectionBody(current); - break; - case Types::Padding: - // No parsing required - break; - default: - return U_UNKNOWN_ITEM_TYPE; + case Types::Section: + parseSectionBody(current); + break; + case Types::Padding: + // No parsing required + break; + default: + return U_UNKNOWN_ITEM_TYPE; } } - + return U_SUCCESS; } @@ -2068,33 +2068,33 @@ USTATUS FfsParser::parseSectionHeader(const UByteArray & section, const UINT32 l if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER)) { return U_INVALID_SECTION; } - + const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); switch (sectionHeader->Type) { - // Special - case EFI_SECTION_COMPRESSION: return parseCompressedSectionHeader(section, localOffset, parent, index, insertIntoTree); - case EFI_SECTION_GUID_DEFINED: return parseGuidedSectionHeader(section, localOffset, parent, index, insertIntoTree); - case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return parseFreeformGuidedSectionHeader(section, localOffset, parent, index, insertIntoTree); - case EFI_SECTION_VERSION: return parseVersionSectionHeader(section, localOffset, parent, index, insertIntoTree); - case PHOENIX_SECTION_POSTCODE: - case INSYDE_SECTION_POSTCODE: return parsePostcodeSectionHeader(section, localOffset, parent, index, insertIntoTree); - // Common - case EFI_SECTION_DISPOSABLE: - case EFI_SECTION_DXE_DEPEX: - case EFI_SECTION_PEI_DEPEX: - case EFI_SECTION_MM_DEPEX: - case EFI_SECTION_PE32: - case EFI_SECTION_PIC: - case EFI_SECTION_TE: - case EFI_SECTION_COMPATIBILITY16: - case EFI_SECTION_USER_INTERFACE: - case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: - case EFI_SECTION_RAW: return parseCommonSectionHeader(section, localOffset, parent, index, insertIntoTree); - // Unknown - default: - USTATUS result = parseCommonSectionHeader(section, localOffset, parent, index, insertIntoTree); - msg(usprintf("%s: section with unknown type %02Xh", __FUNCTION__, sectionHeader->Type), index); - return result; + // Special + case EFI_SECTION_COMPRESSION: return parseCompressedSectionHeader(section, localOffset, parent, index, insertIntoTree); + case EFI_SECTION_GUID_DEFINED: return parseGuidedSectionHeader(section, localOffset, parent, index, insertIntoTree); + case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return parseFreeformGuidedSectionHeader(section, localOffset, parent, index, insertIntoTree); + case EFI_SECTION_VERSION: return parseVersionSectionHeader(section, localOffset, parent, index, insertIntoTree); + case PHOENIX_SECTION_POSTCODE: + case INSYDE_SECTION_POSTCODE: return parsePostcodeSectionHeader(section, localOffset, parent, index, insertIntoTree); + // Common + case EFI_SECTION_DISPOSABLE: + case EFI_SECTION_DXE_DEPEX: + case EFI_SECTION_PEI_DEPEX: + case EFI_SECTION_MM_DEPEX: + case EFI_SECTION_PE32: + case EFI_SECTION_PIC: + case EFI_SECTION_TE: + case EFI_SECTION_COMPATIBILITY16: + case EFI_SECTION_USER_INTERFACE: + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: + case EFI_SECTION_RAW: return parseCommonSectionHeader(section, localOffset, parent, index, insertIntoTree); + // Unknown + default: + USTATUS result = parseCommonSectionHeader(section, localOffset, parent, index, insertIntoTree); + msg(usprintf("%s: section with unknown type %02Xh", __FUNCTION__, sectionHeader->Type), index); + return result; } } @@ -2104,7 +2104,7 @@ USTATUS FfsParser::parseCommonSectionHeader(const UByteArray & section, const UI if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER)) { return U_INVALID_SECTION; } - + // Obtain required information from parent volume UINT8 ffsVersion = 2; UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); @@ -2113,35 +2113,35 @@ USTATUS FfsParser::parseCommonSectionHeader(const UByteArray & section, const UI const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); ffsVersion = pdata->ffsVersion; } - + // Obtain header fields const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); UINT32 headerSize = sizeof(EFI_COMMON_SECTION_HEADER); - if (ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) - headerSize = sizeof(EFI_COMMON_SECTION_HEADER2); + if (ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) + headerSize = sizeof(EFI_COMMON_SECTION_HEADER2); UINT8 type = sectionHeader->Type; // Check sanity again if ((UINT32)section.size() < headerSize) { return U_INVALID_SECTION; } - + UByteArray header = section.left(headerSize); UByteArray body = section.mid(headerSize); - + // Get info UString name = sectionTypeToUString(type) + UString(" section"); UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - type, - section.size(), section.size(), - headerSize, headerSize, - body.size(), body.size()); - + type, + (UINT32)section.size(), (UINT32)section.size(), + headerSize, headerSize, + (UINT32)body.size(), (UINT32)body.size()); + // Add tree item if (insertIntoTree) { index = model->addItem(localOffset, Types::Section, type, name, UString(), info, header, body, UByteArray(), Movable, parent); } - + return U_SUCCESS; } @@ -2150,7 +2150,7 @@ USTATUS FfsParser::parseCompressedSectionHeader(const UByteArray & section, cons // Check sanity if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER)) return U_INVALID_SECTION; - + // Obtain required information from parent volume UINT8 ffsVersion = 2; UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); @@ -2159,14 +2159,14 @@ USTATUS FfsParser::parseCompressedSectionHeader(const UByteArray & section, cons const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); ffsVersion = pdata->ffsVersion; } - + // Obtain header fields UINT32 headerSize; UINT8 compressionType; UINT32 uncompressedLength; const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); const EFI_COMMON_SECTION_HEADER2* section2Header = (const EFI_COMMON_SECTION_HEADER2*)(section.constData()); - + if (ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) { // Check for extended header section const EFI_COMPRESSION_SECTION* compressedSectionHeader = (const EFI_COMPRESSION_SECTION*)(section2Header + 1); if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER2) + sizeof(EFI_COMPRESSION_SECTION)) @@ -2181,36 +2181,36 @@ USTATUS FfsParser::parseCompressedSectionHeader(const UByteArray & section, cons compressionType = compressedSectionHeader->CompressionType; uncompressedLength = compressedSectionHeader->UncompressedLength; } - + // Check sanity again if ((UINT32)section.size() < headerSize) { return U_INVALID_SECTION; } - + UByteArray header = section.left(headerSize); UByteArray body = section.mid(headerSize); - + // Get info UString name = sectionTypeToUString(sectionHeader->Type) + UString(" section"); UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nCompression type: %02Xh\nDecompressed size: %Xh (%u)", - sectionHeader->Type, - section.size(), section.size(), - headerSize, headerSize, - body.size(), body.size(), - compressionType, - uncompressedLength, uncompressedLength); - + sectionHeader->Type, + (UINT32)section.size(), (UINT32)section.size(), + headerSize, headerSize, + (UINT32)body.size(), (UINT32)body.size(), + compressionType, + uncompressedLength, uncompressedLength); + // Add tree item if (insertIntoTree) { index = model->addItem(localOffset, Types::Section, sectionHeader->Type, name, UString(), info, header, body, UByteArray(), Movable, parent); - + // Set section parsing data COMPRESSED_SECTION_PARSING_DATA pdata = {}; pdata.compressionType = compressionType; pdata.uncompressedSize = uncompressedLength; model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); } - + return U_SUCCESS; } @@ -2219,7 +2219,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI // Check sanity if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER)) return U_INVALID_SECTION; - + // Obtain required information from parent volume UINT8 ffsVersion = 2; UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); @@ -2228,7 +2228,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); ffsVersion = pdata->ffsVersion; } - + // Obtain header fields UINT32 headerSize; EFI_GUID guid; @@ -2236,7 +2236,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI UINT16 attributes; const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); const EFI_COMMON_SECTION_HEADER2* section2Header = (const EFI_COMMON_SECTION_HEADER2*)(section.constData()); - + if (ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) { // Check for extended header section const EFI_GUID_DEFINED_SECTION* guidDefinedSectionHeader = (const EFI_GUID_DEFINED_SECTION*)(section2Header + 1); if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER2) + sizeof(EFI_GUID_DEFINED_SECTION)) @@ -2256,7 +2256,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI // Check sanity again if ((UINT32)section.size() < headerSize) return U_INVALID_SECTION; - + // Check for special GUIDed sections UString additionalInfo; UByteArray baGuid((const char*)&guid, sizeof(EFI_GUID)); @@ -2272,10 +2272,10 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI if ((attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == 0) { // Check that AuthStatusValid attribute is set on compressed GUIDed sections msgNoAuthStatusAttribute = true; } - + if ((UINT32)section.size() < headerSize + sizeof(UINT32)) return U_INVALID_SECTION; - + UINT32 crc = *(UINT32*)(section.constData() + headerSize); additionalInfo += UString("\nChecksum type: CRC32"); // Calculate CRC32 of section data @@ -2299,11 +2299,11 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI if ((attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { // Check that ProcessingRequired attribute is set on signed GUIDed sections msgNoProcessingRequiredAttributeSigned = true; } - + // Get certificate type and length if ((UINT32)section.size() < headerSize + sizeof(EFI_CERT_BLOCK_RSA2048_SHA256)) return U_INVALID_SECTION; - + // Adjust dataOffset dataOffset += sizeof(EFI_CERT_BLOCK_RSA2048_SHA256); additionalInfo += UString("\nCertificate type: RSA2048/SHA256"); @@ -2313,30 +2313,30 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI if ((attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { // Check that ProcessingRequired attribute is set on signed GUIDed sections msgNoProcessingRequiredAttributeSigned = true; } - + // Get certificate type and length if ((UINT32)section.size() < headerSize + sizeof(WIN_CERTIFICATE)) return U_INVALID_SECTION; - + const WIN_CERTIFICATE* winCertificate = (const WIN_CERTIFICATE*)(section.constData() + headerSize); UINT32 certLength = winCertificate->Length; UINT16 certType = winCertificate->CertificateType; - + // Adjust dataOffset dataOffset += certLength; - + // Check section size once again if ((UINT32)section.size() < dataOffset) return U_INVALID_SECTION; - + // Check certificate type if (certType == WIN_CERT_TYPE_EFI_GUID) { additionalInfo += UString("\nCertificate type: UEFI"); - + // Get certificate GUID const WIN_CERTIFICATE_UEFI_GUID* winCertificateUefiGuid = (const WIN_CERTIFICATE_UEFI_GUID*)(section.constData() + headerSize); UByteArray certTypeGuid((const char*)&winCertificateUefiGuid->CertType, sizeof(EFI_GUID)); - + if (certTypeGuid == EFI_CERT_TYPE_RSA2048_SHA256_GUID) { additionalInfo += UString("\nCertificate subtype: RSA2048/SHA256"); } @@ -2355,33 +2355,33 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI else if ((attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == EFI_GUIDED_SECTION_PROCESSING_REQUIRED) { msgProcessingRequiredAttributeOnUnknownGuidedSection = true; } - + UByteArray header = section.left(dataOffset); UByteArray body = section.mid(dataOffset); - + // Get info UString name = guidToUString(guid); UString info = UString("Section GUID: ") + guidToUString(guid, false) + - usprintf("\nType: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nData offset: %Xh\nAttributes: %04Xh", - sectionHeader->Type, - section.size(), section.size(), - header.size(), header.size(), - body.size(), body.size(), - dataOffset, - attributes); - + usprintf("\nType: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nData offset: %Xh\nAttributes: %04Xh", + sectionHeader->Type, + (UINT32)section.size(), (UINT32)section.size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + dataOffset, + attributes); + // Append additional info info += additionalInfo; - + // Add tree item if (insertIntoTree) { index = model->addItem(localOffset, Types::Section, sectionHeader->Type, name, UString(), info, header, body, UByteArray(), Movable, parent); - + // Set parsing data GUIDED_SECTION_PARSING_DATA pdata = {}; pdata.guid = guid; model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); - + // Show messages if (msgSignedSectionFound) msg(usprintf("%s: section signature may become invalid after any modification", __FUNCTION__), index); @@ -2400,7 +2400,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI if (msgProcessingRequiredAttributeOnUnknownGuidedSection) msg(usprintf("%s: processing required bit set for GUIDed section with unknown GUID", __FUNCTION__), index); } - + return U_SUCCESS; } @@ -2409,7 +2409,7 @@ USTATUS FfsParser::parseFreeformGuidedSectionHeader(const UByteArray & section, // Check sanity if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER)) return U_INVALID_SECTION; - + // Obtain required information from parent volume UINT8 ffsVersion = 2; UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); @@ -2418,14 +2418,14 @@ USTATUS FfsParser::parseFreeformGuidedSectionHeader(const UByteArray & section, const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); ffsVersion = pdata->ffsVersion; } - + // Obtain header fields UINT32 headerSize; EFI_GUID guid; UINT8 type; const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); const EFI_COMMON_SECTION_HEADER2* section2Header = (const EFI_COMMON_SECTION_HEADER2*)(section.constData()); - + if (ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) { // Check for extended header section const EFI_FREEFORM_SUBTYPE_GUID_SECTION* fsgSectionHeader = (const EFI_FREEFORM_SUBTYPE_GUID_SECTION*)(section2Header + 1); if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER2) + sizeof(EFI_FREEFORM_SUBTYPE_GUID_SECTION)) @@ -2440,36 +2440,36 @@ USTATUS FfsParser::parseFreeformGuidedSectionHeader(const UByteArray & section, guid = fsgSectionHeader->SubTypeGuid; type = sectionHeader->Type; } - + // Check sanity again if ((UINT32)section.size() < headerSize) return U_INVALID_SECTION; - + UByteArray header = section.left(headerSize); UByteArray body = section.mid(headerSize); - + // Get info UString name = sectionTypeToUString(type) + (" section"); UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nSubtype GUID: ", - type, - section.size(), section.size(), - header.size(), header.size(), - body.size(), body.size()) - + guidToUString(guid, false); - + type, + (UINT32)section.size(), (UINT32)section.size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size()) + + guidToUString(guid, false); + // Add tree item if (insertIntoTree) { index = model->addItem(localOffset, Types::Section, type, name, UString(), info, header, body, UByteArray(), Movable, parent); - + // Set parsing data FREEFORM_GUIDED_SECTION_PARSING_DATA pdata = {}; pdata.guid = guid; model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); - + // Rename section model->setName(index, guidToUString(guid)); } - + return U_SUCCESS; } @@ -2478,7 +2478,7 @@ USTATUS FfsParser::parseVersionSectionHeader(const UByteArray & section, const U // Check sanity if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER)) return U_INVALID_SECTION; - + // Obtain required information from parent volume UINT8 ffsVersion = 2; UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); @@ -2487,14 +2487,14 @@ USTATUS FfsParser::parseVersionSectionHeader(const UByteArray & section, const U const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); ffsVersion = pdata->ffsVersion; } - + // Obtain header fields UINT32 headerSize; UINT16 buildNumber; UINT8 type; const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(section.constData()); const EFI_COMMON_SECTION_HEADER2* section2Header = (const EFI_COMMON_SECTION_HEADER2*)(section.constData()); - + if (ffsVersion == 3 && uint24ToUint32(sectionHeader->Size) == EFI_SECTION2_IS_USED) { // Check for extended header section const EFI_VERSION_SECTION* versionHeader = (const EFI_VERSION_SECTION*)(section2Header + 1); headerSize = sizeof(EFI_COMMON_SECTION_HEADER2) + sizeof(EFI_VERSION_SECTION); @@ -2507,28 +2507,28 @@ USTATUS FfsParser::parseVersionSectionHeader(const UByteArray & section, const U buildNumber = versionHeader->BuildNumber; type = sectionHeader->Type; } - + // Check sanity again if ((UINT32)section.size() < headerSize) return U_INVALID_SECTION; - + UByteArray header = section.left(headerSize); UByteArray body = section.mid(headerSize); - + // Get info UString name = sectionTypeToUString(type) + (" section"); UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nBuild number: %u", - type, - section.size(), section.size(), - header.size(), header.size(), - body.size(), body.size(), - buildNumber); - + type, + (UINT32)section.size(), (UINT32)section.size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + buildNumber); + // Add tree item if (insertIntoTree) { index = model->addItem(localOffset, Types::Section, type, name, UString(), info, header, body, UByteArray(), Movable, parent); } - + return U_SUCCESS; } @@ -2537,7 +2537,7 @@ USTATUS FfsParser::parsePostcodeSectionHeader(const UByteArray & section, const // Check sanity if ((UINT32)section.size() < sizeof(EFI_COMMON_SECTION_HEADER)) return U_INVALID_SECTION; - + // Obtain required information from parent volume UINT8 ffsVersion = 2; UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); @@ -2546,7 +2546,7 @@ USTATUS FfsParser::parsePostcodeSectionHeader(const UByteArray & section, const const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); ffsVersion = pdata->ffsVersion; } - + // Obtain header fields UINT32 headerSize; UINT32 postCode; @@ -2566,28 +2566,28 @@ USTATUS FfsParser::parsePostcodeSectionHeader(const UByteArray & section, const postCode = postcodeHeader->Postcode; type = sectionHeader->Type; } - + // Check sanity again if ((UINT32)section.size() < headerSize) return U_INVALID_SECTION; - + UByteArray header = section.left(headerSize); UByteArray body = section.mid(headerSize); - + // Get info UString name = sectionTypeToUString(type) + (" section"); UString info = usprintf("Type: %02Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nPostcode: %Xh", - type, - section.size(), section.size(), - header.size(), header.size(), - body.size(), body.size(), - postCode); - + type, + (UINT32)section.size(), (UINT32)section.size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + postCode); + // Add tree item if (insertIntoTree) { index = model->addItem(localOffset, Types::Section, sectionHeader->Type, name, UString(), info, header, body, UByteArray(), Movable, parent); } - + return U_SUCCESS; } @@ -2599,32 +2599,32 @@ USTATUS FfsParser::parseSectionBody(const UModelIndex & index) UByteArray header = model->header(index); if ((UINT32)header.size() < sizeof(EFI_COMMON_SECTION_HEADER)) return U_INVALID_SECTION; - + const EFI_COMMON_SECTION_HEADER* sectionHeader = (const EFI_COMMON_SECTION_HEADER*)(header.constData()); - + switch (sectionHeader->Type) { - // Encapsulation - case EFI_SECTION_COMPRESSION: return parseCompressedSectionBody(index); - case EFI_SECTION_GUID_DEFINED: return parseGuidedSectionBody(index); - case EFI_SECTION_DISPOSABLE: return parseSections(model->body(index), index, true); - // Leaf - case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return parseRawArea(index); - case EFI_SECTION_VERSION: return parseVersionSectionBody(index); - case EFI_SECTION_DXE_DEPEX: - case EFI_SECTION_PEI_DEPEX: - case EFI_SECTION_MM_DEPEX: return parseDepexSectionBody(index); - case EFI_SECTION_TE: return parseTeImageSectionBody(index); - case EFI_SECTION_PE32: - case EFI_SECTION_PIC: return parsePeImageSectionBody(index); - case EFI_SECTION_USER_INTERFACE: return parseUiSectionBody(index); - case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return parseRawArea(index); - case EFI_SECTION_RAW: return parseRawSectionBody(index); - // No parsing needed - case EFI_SECTION_COMPATIBILITY16: - case PHOENIX_SECTION_POSTCODE: - case INSYDE_SECTION_POSTCODE: - default: - return U_SUCCESS; + // Encapsulation + case EFI_SECTION_COMPRESSION: return parseCompressedSectionBody(index); + case EFI_SECTION_GUID_DEFINED: return parseGuidedSectionBody(index); + case EFI_SECTION_DISPOSABLE: return parseSections(model->body(index), index, true); + // Leaf + case EFI_SECTION_FREEFORM_SUBTYPE_GUID: return parseRawArea(index); + case EFI_SECTION_VERSION: return parseVersionSectionBody(index); + case EFI_SECTION_DXE_DEPEX: + case EFI_SECTION_PEI_DEPEX: + case EFI_SECTION_MM_DEPEX: return parseDepexSectionBody(index); + case EFI_SECTION_TE: return parseTeImageSectionBody(index); + case EFI_SECTION_PE32: + case EFI_SECTION_PIC: return parsePeImageSectionBody(index); + case EFI_SECTION_USER_INTERFACE: return parseUiSectionBody(index); + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: return parseRawArea(index); + case EFI_SECTION_RAW: return parseRawSectionBody(index); + // No parsing needed + case EFI_SECTION_COMPATIBILITY16: + case PHOENIX_SECTION_POSTCODE: + case INSYDE_SECTION_POSTCODE: + default: + return U_SUCCESS; } } @@ -2633,7 +2633,7 @@ USTATUS FfsParser::parseCompressedSectionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Obtain required information from parsing data UINT8 compressionType = EFI_NOT_COMPRESSED; UINT32 uncompressedSize = (UINT32)model->body(index).size(); @@ -2643,7 +2643,7 @@ USTATUS FfsParser::parseCompressedSectionBody(const UModelIndex & index) compressionType = readUnaligned(pdata).compressionType; uncompressedSize = readUnaligned(pdata).uncompressedSize; } - + // Decompress section UINT8 algorithm = COMPRESSION_ALGORITHM_NONE; UINT32 dictionarySize = 0; @@ -2654,17 +2654,17 @@ USTATUS FfsParser::parseCompressedSectionBody(const UModelIndex & index) msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index); return U_SUCCESS; } - + // Check reported uncompressed size if (uncompressedSize != (UINT32)decompressed.size()) { msg(usprintf("%s: decompressed size stored in header %Xh (%u) differs from actual %Xh (%u)", - __FUNCTION__, - uncompressedSize, uncompressedSize, - decompressed.size(), decompressed.size()), + __FUNCTION__, + uncompressedSize, uncompressedSize, + (UINT32)decompressed.size(), (UINT32)decompressed.size()), index); - model->addInfo(index, usprintf("\nActual decompressed size: %Xh (%u)", decompressed.size(), decompressed.size())); + model->addInfo(index, usprintf("\nActual decompressed size: %Xh (%u)", (UINT32)decompressed.size(), (UINT32)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 @@ -2680,13 +2680,13 @@ USTATUS FfsParser::parseCompressedSectionBody(const UModelIndex & index) msg(usprintf("%s: can't guess the correct decompression algorithm, both preparse steps are failed", __FUNCTION__), index); } } - + // Add info model->addInfo(index, UString("\nCompression algorithm: ") + compressionTypeToUString(algorithm)); if (algorithm == COMPRESSION_ALGORITHM_LZMA || algorithm == COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY) { model->addInfo(index, usprintf("\nLZMA dictionary size: %Xh", dictionarySize)); } - + // Set compression data if (algorithm != COMPRESSION_ALGORITHM_NONE) { model->setUncompressedData(index, decompressed); @@ -2710,7 +2710,7 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Obtain required information from parsing data EFI_GUID guid = { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0 }}; if (model->hasEmptyParsingData(index) == false) { @@ -2718,7 +2718,7 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) const GUIDED_SECTION_PARSING_DATA* pdata = (const GUIDED_SECTION_PARSING_DATA*)data.constData(); guid = readUnaligned(pdata).guid; } - + // Check if section requires processing UByteArray processed = model->body(index); UByteArray efiDecompressed; @@ -2734,7 +2734,7 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index); return U_SUCCESS; } - + // Check for undecided compression algorithm, this is a special case if (algorithm == COMPRESSION_ALGORITHM_UNDECIDED) { // Try preparse of sections decompressed with Tiano algorithm @@ -2751,9 +2751,9 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) parseCurrentSection = false; } } - + info += UString("\nCompression algorithm: ") + compressionTypeToUString(algorithm); - info += usprintf("\nDecompressed size: %Xh (%u)", processed.size(), processed.size()); + info += usprintf("\nDecompressed size: %Xh (%u)", (UINT32)processed.size(), (UINT32)processed.size()); } // LZMA compressed section else if (baGuid == EFI_GUIDED_SECTION_LZMA @@ -2763,10 +2763,10 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index); return U_SUCCESS; } - + if (algorithm == COMPRESSION_ALGORITHM_LZMA) { info += UString("\nCompression algorithm: LZMA"); - info += usprintf("\nDecompressed size: %Xh (%u)", processed.size(), processed.size()); + info += usprintf("\nDecompressed size: %Xh (%u)", (UINT32)processed.size(), (UINT32)processed.size()); info += usprintf("\nLZMA dictionary size: %Xh", dictionarySize); } else { @@ -2781,10 +2781,10 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index); return U_SUCCESS; } - + if (algorithm == COMPRESSION_ALGORITHM_LZMAF86) { info += UString("\nCompression algorithm: LZMAF86"); - info += usprintf("\nDecompressed size: %Xh (%u)", processed.size(), processed.size()); + info += usprintf("\nDecompressed size: %Xh (%u)", (UINT32)processed.size(), (UINT32)processed.size()); info += usprintf("\nLZMA dictionary size: %Xh", dictionarySize); } else { @@ -2799,30 +2799,30 @@ USTATUS FfsParser::parseGuidedSectionBody(const UModelIndex & index) msg(usprintf("%s: decompression failed with error ", __FUNCTION__) + errorCodeToUString(result), index); return U_SUCCESS; } - + info += UString("\nCompression algorithm: GZip"); - info += usprintf("\nDecompressed size: %Xh (%u)", processed.size(), processed.size()); + info += usprintf("\nDecompressed size: %Xh (%u)", (UINT32)processed.size(), (UINT32)processed.size()); } - + // Add info model->addInfo(index, info); - + // Set parsing data GUIDED_SECTION_PARSING_DATA pdata = {}; pdata.dictionarySize = dictionarySize; model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); - + // Set compression data if (algorithm != COMPRESSION_ALGORITHM_NONE) { model->setUncompressedData(index, processed); model->setCompressed(index, true); } - + if (!parseCurrentSection) { msg(usprintf("%s: GUID defined section can not be processed", __FUNCTION__), index); return U_SUCCESS; } - + return parseSections(processed, index, true); } @@ -2831,14 +2831,14 @@ USTATUS FfsParser::parseVersionSectionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Add info #if QT_VERSION_MAJOR >= 6 model->addInfo(index, UString("\nVersion string: ") + UString::fromUtf16((const char16_t*)model->body(index).constData())); #else model->addInfo(index, UString("\nVersion string: ") + UString::fromUtf16((const CHAR16*)model->body(index).constData())); #endif - + return U_SUCCESS; } @@ -2847,122 +2847,122 @@ USTATUS FfsParser::parseDepexSectionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + UByteArray body = model->body(index); UString parsed; - + // Check data to be present if (body.size() < 2) { // 2 is a minimal sane value, i.e TRUE + END msg(usprintf("%s: DEPEX section too short", __FUNCTION__), index); return U_DEPEX_PARSE_FAILED; } - + const EFI_GUID * guid; const UINT8* current = (const UINT8*)body.constData(); - + // Special cases of first opcode switch (*current) { - case EFI_DEP_BEFORE: - if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { - msg(usprintf("%s: DEPEX section too long for a section starting with BEFORE opcode", __FUNCTION__), index); - return U_SUCCESS; - } - guid = (const EFI_GUID*)(current + EFI_DEP_OPCODE_SIZE); - parsed += UString("\nBEFORE ") + guidToUString(readUnaligned(guid)); - current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); - if (*current != EFI_DEP_END){ - msg(usprintf("%s: DEPEX section ends with non-END opcode", __FUNCTION__), index); - return U_SUCCESS; - } - return U_SUCCESS; - case EFI_DEP_AFTER: - if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)){ - msg(usprintf("%s: DEPEX section too long for a section starting with AFTER opcode", __FUNCTION__), index); - return U_SUCCESS; - } - guid = (const EFI_GUID*)(current + EFI_DEP_OPCODE_SIZE); - parsed += UString("\nAFTER ") + guidToUString(readUnaligned(guid)); - current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); - if (*current != EFI_DEP_END) { - msg(usprintf("%s: DEPEX section ends with non-END opcode", __FUNCTION__), index); - return U_SUCCESS; - } - return U_SUCCESS; - case EFI_DEP_SOR: - if (body.size() <= 2 * EFI_DEP_OPCODE_SIZE) { - msg(usprintf("%s: DEPEX section too short for a section starting with SOR opcode", __FUNCTION__), index); - return U_SUCCESS; - } - parsed += UString("\nSOR"); - current += EFI_DEP_OPCODE_SIZE; - break; - } - - // Parse the rest of depex - while (current - (const UINT8*)body.constData() < body.size()) { - switch (*current) { - case EFI_DEP_BEFORE: { - msg(usprintf("%s: misplaced BEFORE opcode", __FUNCTION__), index); - return U_SUCCESS; - } - case EFI_DEP_AFTER: { - msg(usprintf("%s: misplaced AFTER opcode", __FUNCTION__), index); - return U_SUCCESS; - } - case EFI_DEP_SOR: { - msg(usprintf("%s: misplaced SOR opcode", __FUNCTION__), index); - return U_SUCCESS; - } - case EFI_DEP_PUSH: - // Check that the rest of depex has correct size - if ((UINT32)body.size() - (UINT32)(current - (const UINT8*)body.constData()) <= EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { - parsed.clear(); - msg(usprintf("%s: remains of DEPEX section too short for PUSH opcode", __FUNCTION__), index); + case EFI_DEP_BEFORE: + if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { + msg(usprintf("%s: DEPEX section too long for a section starting with BEFORE opcode", __FUNCTION__), index); return U_SUCCESS; } guid = (const EFI_GUID*)(current + EFI_DEP_OPCODE_SIZE); - parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid)); + parsed += UString("\nBEFORE ") + guidToUString(readUnaligned(guid)); current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); - break; - case EFI_DEP_AND: - parsed += UString("\nAND"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_OR: - parsed += UString("\nOR"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_NOT: - parsed += UString("\nNOT"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_TRUE: - parsed += UString("\nTRUE"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_FALSE: - parsed += UString("\nFALSE"); - current += EFI_DEP_OPCODE_SIZE; - break; - case EFI_DEP_END: - parsed += UString("\nEND"); - current += EFI_DEP_OPCODE_SIZE; - // Check that END is the last opcode - if (current - (const UINT8*)body.constData() < body.size()) { - parsed.clear(); + if (*current != EFI_DEP_END){ msg(usprintf("%s: DEPEX section ends with non-END opcode", __FUNCTION__), index); + return U_SUCCESS; } - break; - default: - msg(usprintf("%s: unknown opcode %02Xh", __FUNCTION__, *current), index); return U_SUCCESS; + case EFI_DEP_AFTER: + if (body.size() != 2 * EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)){ + msg(usprintf("%s: DEPEX section too long for a section starting with AFTER opcode", __FUNCTION__), index); + return U_SUCCESS; + } + guid = (const EFI_GUID*)(current + EFI_DEP_OPCODE_SIZE); + parsed += UString("\nAFTER ") + guidToUString(readUnaligned(guid)); + current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); + if (*current != EFI_DEP_END) { + msg(usprintf("%s: DEPEX section ends with non-END opcode", __FUNCTION__), index); + return U_SUCCESS; + } + return U_SUCCESS; + case EFI_DEP_SOR: + if (body.size() <= 2 * EFI_DEP_OPCODE_SIZE) { + msg(usprintf("%s: DEPEX section too short for a section starting with SOR opcode", __FUNCTION__), index); + return U_SUCCESS; + } + parsed += UString("\nSOR"); + current += EFI_DEP_OPCODE_SIZE; break; + } + + // Parse the rest of depex + while (current - (const UINT8*)body.constData() < body.size()) { + switch (*current) { + case EFI_DEP_BEFORE: { + msg(usprintf("%s: misplaced BEFORE opcode", __FUNCTION__), index); + return U_SUCCESS; + } + case EFI_DEP_AFTER: { + msg(usprintf("%s: misplaced AFTER opcode", __FUNCTION__), index); + return U_SUCCESS; + } + case EFI_DEP_SOR: { + msg(usprintf("%s: misplaced SOR opcode", __FUNCTION__), index); + return U_SUCCESS; + } + case EFI_DEP_PUSH: + // Check that the rest of depex has correct size + if ((UINT32)body.size() - (UINT32)(current - (const UINT8*)body.constData()) <= EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID)) { + parsed.clear(); + msg(usprintf("%s: remains of DEPEX section too short for PUSH opcode", __FUNCTION__), index); + return U_SUCCESS; + } + guid = (const EFI_GUID*)(current + EFI_DEP_OPCODE_SIZE); + parsed += UString("\nPUSH ") + guidToUString(readUnaligned(guid)); + current += EFI_DEP_OPCODE_SIZE + sizeof(EFI_GUID); + break; + case EFI_DEP_AND: + parsed += UString("\nAND"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_OR: + parsed += UString("\nOR"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_NOT: + parsed += UString("\nNOT"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_TRUE: + parsed += UString("\nTRUE"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_FALSE: + parsed += UString("\nFALSE"); + current += EFI_DEP_OPCODE_SIZE; + break; + case EFI_DEP_END: + parsed += UString("\nEND"); + current += EFI_DEP_OPCODE_SIZE; + // Check that END is the last opcode + if (current - (const UINT8*)body.constData() < body.size()) { + parsed.clear(); + msg(usprintf("%s: DEPEX section ends with non-END opcode", __FUNCTION__), index); + } + break; + default: + msg(usprintf("%s: unknown opcode %02Xh", __FUNCTION__, *current), index); + return U_SUCCESS; + break; } } - + // Add info model->addInfo(index, UString("\nParsed expression:") + parsed); - + return U_SUCCESS; } @@ -2971,19 +2971,19 @@ USTATUS FfsParser::parseUiSectionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + #if QT_VERSION_MAJOR >= 6 UString text = UString::fromUtf16((const char16_t*)model->body(index).constData()); #else UString text = UString::fromUtf16((const CHAR16*)model->body(index).constData()); #endif - + // Add info model->addInfo(index, UString("\nText: ") + text); - + // Rename parent file model->setText(model->findParentOfType(index, Types::File), text); - + return U_SUCCESS; } @@ -3001,7 +3001,7 @@ USTATUS FfsParser::parseAprioriRawSection(const UByteArray & body, UString & par parsed += UString("\n") + guidToUString(readUnaligned(guid)); } } - + return U_SUCCESS; } @@ -3010,12 +3010,12 @@ USTATUS FfsParser::parseRawSectionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Check for apriori file UModelIndex parentFile = model->findParentOfType(index, Types::File); if (!parentFile.isValid()) return U_INVALID_FILE; //TODO: better return code - + // Get parent file parsing data UByteArray parentFileGuid(model->header(parentFile).constData(), sizeof(EFI_GUID)); if (parentFileGuid == EFI_PEI_APRIORI_FILE_GUID) { // PEI apriori file @@ -3048,7 +3048,7 @@ USTATUS FfsParser::parseRawSectionBody(const UModelIndex & index) // Parse AMI vendor hash file return parseVendorHashFile(parentFileGuid, index); } - + // Parse as raw area return parseRawArea(index); } @@ -3059,14 +3059,14 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Get section body UByteArray body = model->body(index); if ((UINT32)body.size() < sizeof(EFI_IMAGE_DOS_HEADER)) { msg(usprintf("%s: section body size is smaller than DOS header size", __FUNCTION__), index); return U_SUCCESS; } - + UString info; const EFI_IMAGE_DOS_HEADER* dosHeader = (const EFI_IMAGE_DOS_HEADER*)body.constData(); if (dosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) { @@ -3075,7 +3075,7 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index) model->addInfo(index, info); return U_SUCCESS; } - + const EFI_IMAGE_PE_HEADER* peHeader = (EFI_IMAGE_PE_HEADER*)(body.constData() + dosHeader->e_lfanew); if (body.size() < (UINT8*)peHeader - (UINT8*)dosHeader) { info += UString("\nDOS header: invalid"); @@ -3083,14 +3083,14 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index) model->addInfo(index, info); return U_SUCCESS; } - + if (peHeader->Signature != EFI_IMAGE_PE_SIGNATURE) { info += usprintf("\nPE signature: %08Xh, invalid", peHeader->Signature); msg(usprintf("%s: PE32 image with invalid PE signature", __FUNCTION__), index); model->addInfo(index, info); return U_SUCCESS; } - + const EFI_IMAGE_FILE_HEADER* imageFileHeader = (const EFI_IMAGE_FILE_HEADER*)(peHeader + 1); if (body.size() < (UINT8*)imageFileHeader - (UINT8*)dosHeader) { info += UString("\nPE header: invalid"); @@ -3098,15 +3098,15 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index) model->addInfo(index, info); return U_SUCCESS; } - + info += usprintf("\nDOS signature: %04Xh\nPE signature: %08Xh", - dosHeader->e_magic, - peHeader->Signature) + - UString("\nMachine type: ") + machineTypeToUString(imageFileHeader->Machine) + - usprintf("\nNumber of sections: %u\nCharacteristics: %04Xh", - imageFileHeader->NumberOfSections, - imageFileHeader->Characteristics); - + dosHeader->e_magic, + peHeader->Signature) + + UString("\nMachine type: ") + machineTypeToUString(imageFileHeader->Machine) + + usprintf("\nNumber of sections: %u\nCharacteristics: %04Xh", + imageFileHeader->NumberOfSections, + imageFileHeader->Characteristics); + EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader; optionalHeader.H32 = (const EFI_IMAGE_OPTIONAL_HEADER32*)(imageFileHeader + 1); if (body.size() < (UINT8*)optionalHeader.H32 - (UINT8*)dosHeader) { @@ -3115,28 +3115,28 @@ USTATUS FfsParser::parsePeImageSectionBody(const UModelIndex & index) model->addInfo(index, info); return U_SUCCESS; } - + if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC) { info += usprintf("\nOptional header signature: %04Xh\nSubsystem: %04Xh\nAddress of entry point: %Xh\nBase of code: %Xh\nImage base: %Xh", - optionalHeader.H32->Magic, - optionalHeader.H32->Subsystem, - optionalHeader.H32->AddressOfEntryPoint, - optionalHeader.H32->BaseOfCode, - optionalHeader.H32->ImageBase); + optionalHeader.H32->Magic, + optionalHeader.H32->Subsystem, + optionalHeader.H32->AddressOfEntryPoint, + optionalHeader.H32->BaseOfCode, + optionalHeader.H32->ImageBase); } else if (optionalHeader.H32->Magic == EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC) { info += usprintf("\nOptional header signature: %04Xh\nSubsystem: %04Xh\nAddress of entry point: %Xh\nBase of code: %Xh\nImage base: %" PRIX64 "h", - optionalHeader.H64->Magic, - optionalHeader.H64->Subsystem, - optionalHeader.H64->AddressOfEntryPoint, - optionalHeader.H64->BaseOfCode, - optionalHeader.H64->ImageBase); + optionalHeader.H64->Magic, + optionalHeader.H64->Subsystem, + optionalHeader.H64->AddressOfEntryPoint, + optionalHeader.H64->BaseOfCode, + optionalHeader.H64->ImageBase); } else { info += usprintf("\nOptional header signature: %04Xh, unknown", optionalHeader.H32->Magic); msg(usprintf("%s: PE32 image with invalid optional PE header signature", __FUNCTION__), index); } - + model->addInfo(index, info); return U_SUCCESS; } @@ -3147,14 +3147,14 @@ USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index) // Check sanity if (!index.isValid()) return U_INVALID_PARAMETER; - + // Get section body UByteArray body = model->body(index); if ((UINT32)body.size() < sizeof(EFI_IMAGE_TE_HEADER)) { msg(usprintf("%s: section body size is smaller than TE header size", __FUNCTION__), index); return U_SUCCESS; } - + UString info; const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)body.constData(); if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) { @@ -3163,28 +3163,28 @@ USTATUS FfsParser::parseTeImageSectionBody(const UModelIndex & index) } else { info += usprintf("\nSignature: %04Xh", teHeader->Signature) + - UString("\nMachine type: ") + machineTypeToUString(teHeader->Machine) + - usprintf("\nNumber of sections: %u\nSubsystem: %02Xh\nStripped size: %Xh (%u)\n" - "Base of code: %Xh\nAddress of entry point: %Xh\nImage base: %" PRIX64 "h\nAdjusted image base: %" PRIX64 "h", - teHeader->NumberOfSections, - teHeader->Subsystem, - teHeader->StrippedSize, teHeader->StrippedSize, - teHeader->BaseOfCode, - teHeader->AddressOfEntryPoint, - teHeader->ImageBase, - teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER)); + UString("\nMachine type: ") + machineTypeToUString(teHeader->Machine) + + usprintf("\nNumber of sections: %u\nSubsystem: %02Xh\nStripped size: %Xh (%u)\n" + "Base of code: %Xh\nAddress of entry point: %Xh\nImage base: %" PRIX64 "h\nAdjusted image base: %" PRIX64 "h", + teHeader->NumberOfSections, + teHeader->Subsystem, + teHeader->StrippedSize, teHeader->StrippedSize, + teHeader->BaseOfCode, + teHeader->AddressOfEntryPoint, + teHeader->ImageBase, + teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER)); } - + // Update parsing data TE_IMAGE_SECTION_PARSING_DATA pdata = {}; pdata.imageBaseType = EFI_IMAGE_TE_BASE_OTHER; // Will be determined later pdata.originalImageBase = (UINT32)teHeader->ImageBase; pdata.adjustedImageBase = (UINT32)(teHeader->ImageBase + teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER)); model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); - + // Add TE info model->addInfo(index, info); - + return U_SUCCESS; } @@ -3194,29 +3194,29 @@ USTATUS FfsParser::performSecondPass(const UModelIndex & index) // Sanity check if (!index.isValid() || !lastVtf.isValid()) return U_INVALID_PARAMETER; - + // Check for compressed lastVtf if (model->compressed(lastVtf)) { msg(usprintf("%s: the last VTF appears inside compressed item, the image may be damaged", __FUNCTION__), lastVtf); return U_SUCCESS; } - + // Calculate address difference const UINT32 vtfSize = (UINT32)(model->header(lastVtf).size() + model->body(lastVtf).size() + model->tail(lastVtf).size()); addressDiff = 0xFFFFFFFFULL - model->base(lastVtf) - vtfSize + 1; - + // Parse reset vector data parseResetVectorData(); - + // Find and parse FIT parseFit(index); - + // Check protected ranges checkProtectedRanges(index); - + // Check TE files to have original or adjusted base checkTeImageBase(index); - + return U_SUCCESS; } @@ -3225,28 +3225,28 @@ USTATUS FfsParser::parseResetVectorData() // Sanity check if (!lastVtf.isValid()) return U_SUCCESS; - + // Check VTF to have enough space at the end to fit Reset Vector Data UByteArray vtf = model->header(lastVtf) + model->body(lastVtf) + model->tail(lastVtf); if ((UINT32)vtf.size() < sizeof(X86_RESET_VECTOR_DATA)) return U_SUCCESS; - + const X86_RESET_VECTOR_DATA* resetVectorData = (const X86_RESET_VECTOR_DATA*)(vtf.constData() + vtf.size() - sizeof(X86_RESET_VECTOR_DATA)); - + // Add info UString info = usprintf("\nAP entry vector: %02X %02X %02X %02X %02X %02X %02X %02X\n" "Reset vector: %02X %02X %02X %02X %02X %02X %02X %02X\n" "PEI core entry point: %08Xh\n" "AP startup segment: %08X\n" "BootFV base address: %08X\n", - resetVectorData->ApEntryVector[0], resetVectorData->ApEntryVector[1], resetVectorData->ApEntryVector[2], resetVectorData->ApEntryVector[3], - resetVectorData->ApEntryVector[4], resetVectorData->ApEntryVector[5], resetVectorData->ApEntryVector[6], resetVectorData->ApEntryVector[7], - resetVectorData->ResetVector[0], resetVectorData->ResetVector[1], resetVectorData->ResetVector[2], resetVectorData->ResetVector[3], - resetVectorData->ResetVector[4], resetVectorData->ResetVector[5], resetVectorData->ResetVector[6], resetVectorData->ResetVector[7], - resetVectorData->PeiCoreEntryPoint, - resetVectorData->ApStartupSegment, - resetVectorData->BootFvBaseAddress); - + resetVectorData->ApEntryVector[0], resetVectorData->ApEntryVector[1], resetVectorData->ApEntryVector[2], resetVectorData->ApEntryVector[3], + resetVectorData->ApEntryVector[4], resetVectorData->ApEntryVector[5], resetVectorData->ApEntryVector[6], resetVectorData->ApEntryVector[7], + resetVectorData->ResetVector[0], resetVectorData->ResetVector[1], resetVectorData->ResetVector[2], resetVectorData->ResetVector[3], + resetVectorData->ResetVector[4], resetVectorData->ResetVector[5], resetVectorData->ResetVector[6], resetVectorData->ResetVector[7], + resetVectorData->PeiCoreEntryPoint, + resetVectorData->ApStartupSegment, + resetVectorData->BootFvBaseAddress); + model->addInfo(lastVtf, info); return U_SUCCESS; } @@ -3256,7 +3256,7 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_SUCCESS; - + // Determine relocation type of uncompressed TE image sections if (model->compressed(index) == false && model->type(index) == Types::Section @@ -3271,12 +3271,12 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index) originalImageBase = readUnaligned(pdata).originalImageBase; adjustedImageBase = readUnaligned(pdata).adjustedImageBase; } - + if (originalImageBase != 0 || adjustedImageBase != 0) { // Check data memory address to be equal to either OriginalImageBase or AdjustedImageBase UINT64 address = addressDiff + model->base(index); UINT32 base = (UINT32)(address + model->header(index).size()); - + if (originalImageBase == base) { imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL; } @@ -3296,12 +3296,12 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index) } } } - + // Show message if imageBaseType is still unknown if (imageBaseType == EFI_IMAGE_TE_BASE_OTHER) { msg(usprintf("%s: TE image base is neither zero, nor original, nor adjusted, nor top-swapped", __FUNCTION__), index); } - + // Update parsing data TE_IMAGE_SECTION_PARSING_DATA pdata = {}; pdata.imageBaseType = imageBaseType; @@ -3310,12 +3310,12 @@ USTATUS FfsParser::checkTeImageBase(const UModelIndex & index) model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata))); } } - + // Process child items for (int i = 0; i < model->rowCount(index); i++) { checkTeImageBase(index.model()->index(i, 0, index)); } - + return U_SUCCESS; } @@ -3324,10 +3324,10 @@ USTATUS FfsParser::addInfoRecursive(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Add offset model->addInfo(index, usprintf("Offset: %Xh\n", model->offset(index)), false); - + // Add current base if the element is not compressed // or it's compressed, but its parent isn't if ((!model->compressed(index)) || (index.parent().isValid() && !model->compressed(index.parent()))) { @@ -3347,12 +3347,12 @@ USTATUS FfsParser::addInfoRecursive(const UModelIndex & index) model->addInfo(index, usprintf("Base: %Xh\n", model->base(index)), false); } model->addInfo(index, usprintf("Fixed: %s\n", model->fixed(index) ? "Yes" : "No"), false); - + // Process child items for (int i = 0; i < model->rowCount(index); i++) { addInfoRecursive(index.model()->index(i, 0, index)); } - + return U_SUCCESS; } @@ -3361,7 +3361,7 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Calculate digest for BG-protected ranges UByteArray protectedParts; bool bgProtectedRangeFound = false; @@ -3382,11 +3382,11 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) } catch (...) { bgProtectedRangeFound = false; } - + if (bgProtectedRangeFound) { UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); sha256(protectedParts.constData(), protectedParts.size(), digest.data()); - + if (digest != bgBpDigest) { msg(usprintf("%s: BG-protected ranges hash mismatch, opened image may refuse to boot", __FUNCTION__), index); } @@ -3394,7 +3394,7 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) else if (bgBootPolicyFound) { msg(usprintf("%s: BootPolicy doesn't define any BG-protected ranges", __FUNCTION__), index); } - + // Calculate digests for vendor-protected ranges for (UINT32 i = 0; i < (UINT32)bgProtectedRanges.size(); i++) { if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD @@ -3411,16 +3411,16 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) else { bgProtectedRanges[i].Offset = model->base(dxeRootVolumeIndex); protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); - + UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); sha256(protectedParts.constData(), protectedParts.size(), digest.data()); - + if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("%s: old AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__, - bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), + bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), model->findByBase(bgProtectedRanges[i].Offset)); } - + markProtectedRangeRecursive(index, bgProtectedRanges[i]); } } @@ -3439,37 +3439,37 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) bgProtectedRanges[i].Offset = model->base(dxeRootVolumeIndex); bgProtectedRanges[i].Size = (UINT32)(model->header(dxeRootVolumeIndex).size() + model->body(dxeRootVolumeIndex).size() + model->tail(dxeRootVolumeIndex).size()); protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); - + UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); sha256(protectedParts.constData(), protectedParts.size(), digest.data()); - + if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("%s: post-IBB protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__, - bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), + bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), model->findByBase(bgProtectedRanges[i].Offset)); } - + markProtectedRangeRecursive(index, bgProtectedRanges[i]); } } } else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW - && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF - && bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { - + && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF + && bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { + if ((UINT64)bgProtectedRanges[i].Offset >= addressDiff) { bgProtectedRanges[i].Offset -= (UINT32)addressDiff; protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); - + UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); sha256(protectedParts.constData(), protectedParts.size(), digest.data()); - + if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("%s: AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__, - bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), + bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), model->findByBase(bgProtectedRanges[i].Offset)); } - + markProtectedRangeRecursive(index, bgProtectedRanges[i]); } else { // TODO: Explore this. @@ -3477,41 +3477,41 @@ USTATUS FfsParser::checkProtectedRanges(const UModelIndex & index) } } else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX - && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF - && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { + && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF + && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { bgProtectedRanges[i].Offset += (UINT32)bgProtectedRegionsBase; protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); - + UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); sha256(protectedParts.constData(), protectedParts.size(), digest.data()); - + if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("%s: Phoenix protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__, - bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), + bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), model->findByBase(bgProtectedRanges[i].Offset)); } - + markProtectedRangeRecursive(index, bgProtectedRanges[i]); } else if (bgProtectedRanges[i].Type == BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT - && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF - && bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { + && bgProtectedRanges[i].Size != 0 && bgProtectedRanges[i].Size != 0xFFFFFFFF + && bgProtectedRanges[i].Offset != 0 && bgProtectedRanges[i].Offset != 0xFFFFFFFF) { bgProtectedRanges[i].Offset -= (UINT32)addressDiff; protectedParts = openedImage.mid(bgProtectedRanges[i].Offset, bgProtectedRanges[i].Size); - + UByteArray digest(SHA256_DIGEST_SIZE, '\x00'); sha256(protectedParts.constData(), protectedParts.size(), digest.data()); - + if (digest != bgProtectedRanges[i].Hash) { msg(usprintf("%s: Microsoft protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot", __FUNCTION__, - bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), + bgProtectedRanges[i].Offset, bgProtectedRanges[i].Offset + bgProtectedRanges[i].Size), model->findByBase(bgProtectedRanges[i].Offset)); } - + markProtectedRangeRecursive(index, bgProtectedRanges[i]); } } - + return U_SUCCESS; } @@ -3519,7 +3519,7 @@ USTATUS FfsParser::markProtectedRangeRecursive(const UModelIndex & index, const { if (!index.isValid()) return U_SUCCESS; - + // Mark compressed items UModelIndex parentIndex = model->parent(index); if (parentIndex.isValid() && model->compressed(index) && model->compressed(parentIndex)) { @@ -3529,7 +3529,7 @@ USTATUS FfsParser::markProtectedRangeRecursive(const UModelIndex & index, const else { UINT32 currentOffset = model->base(index); UINT32 currentSize = (UINT32)(model->header(index).size() + model->body(index).size() + model->tail(index).size()); - + if (std::min(currentOffset + currentSize, range.Offset + range.Size) > std::max(currentOffset, range.Offset)) { if (range.Offset <= currentOffset && currentOffset + currentSize <= range.Offset + range.Size) { // Mark as fully in range if (range.Type == BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB) { @@ -3544,11 +3544,11 @@ USTATUS FfsParser::markProtectedRangeRecursive(const UModelIndex & index, const } } } - + for (int i = 0; i < model->rowCount(index); i++) { markProtectedRangeRecursive(index.model()->index(i, 0, index), range); } - + return U_SUCCESS; } @@ -3556,18 +3556,18 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel { if (!index.isValid()) return EFI_INVALID_PARAMETER; - + if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX) { const UByteArray &body = model->body(index); UINT32 size = (UINT32)body.size(); - + // File too small to have even a signature if (size < sizeof(BG_VENDOR_HASH_FILE_SIGNATURE_PHOENIX)) { msg(usprintf("%s: unknown or corrupted Phoenix hash file found", __FUNCTION__), index); model->setText(index, UString("Phoenix hash file")); return U_INVALID_FILE; } - + const BG_VENDOR_HASH_FILE_HEADER_PHOENIX* header = (const BG_VENDOR_HASH_FILE_HEADER_PHOENIX*)body.constData(); if (header->Signature == BG_VENDOR_HASH_FILE_SIGNATURE_PHOENIX) { if (size < sizeof(BG_VENDOR_HASH_FILE_HEADER_PHOENIX) || @@ -3576,13 +3576,13 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel model->setText(index, UString("Phoenix hash file")); return U_INVALID_FILE; } - + if (header->NumEntries > 0) { bool protectedRangesFound = false; for (UINT32 i = 0; i < header->NumEntries; i++) { protectedRangesFound = true; const BG_VENDOR_HASH_FILE_ENTRY* entry = (const BG_VENDOR_HASH_FILE_ENTRY*)(header + 1) + i; - + BG_PROTECTED_RANGE range = {}; range.Offset = entry->Offset; range.Size = entry->Size; @@ -3590,7 +3590,7 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel range.Type = BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX; bgProtectedRanges.push_back(range); } - + if (protectedRangesFound) { securityInfo += usprintf("Phoenix hash file found at base %Xh\nProtected ranges:", model->base(index)); for (UINT32 i = 0; i < header->NumEntries; i++) { @@ -3602,13 +3602,13 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel } securityInfo += UString("\n------------------------------------------------------------------------\n\n"); } - + msg(usprintf("%s: Phoenix hash file found", __FUNCTION__), index); } else { msg(usprintf("%s: empty Phoenix hash file found", __FUNCTION__), index); } - + model->setText(index, UString("Phoenix hash file")); } } @@ -3630,7 +3630,7 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel range.Type = BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW; bgProtectedRanges.push_back(range); } - + if (protectedRangesFound) { securityInfo += usprintf("New AMI hash file found at base %Xh\nProtected ranges:", model->base(fileIndex)); for (UINT32 i = 0; i < NumEntries; i++) { @@ -3642,7 +3642,7 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel } securityInfo += UString("\n------------------------------------------------------------------------\n\n"); } - + msg(usprintf("%s: new AMI hash file found", __FUNCTION__), fileIndex); } else if (size == sizeof(BG_VENDOR_HASH_FILE_HEADER_AMI_OLD)) { @@ -3653,14 +3653,14 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel securityInfo += usprintf("%02X", entry->Hash[i]); } securityInfo += UString("\n------------------------------------------------------------------------\n\n"); - + BG_PROTECTED_RANGE range = {}; range.Offset = 0; range.Size = entry->Size; range.Hash = UByteArray((const char*)entry->Hash, sizeof(entry->Hash)); range.Type = BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD; bgProtectedRanges.push_back(range); - + msg(usprintf("%s: old AMI hash file found", __FUNCTION__), fileIndex); } else { @@ -3670,10 +3670,10 @@ USTATUS FfsParser::parseVendorHashFile(const UByteArray & fileGuid, const UModel else { msg(usprintf("%s: empty AMI hash file found", __FUNCTION__), fileIndex); } - + model->setText(fileIndex, UString("AMI hash file")); } - + return U_SUCCESS; } @@ -3690,23 +3690,23 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) // Check sanity if (!index.isValid()) return EFI_INVALID_PARAMETER; - + // Search for FIT UModelIndex fitIndex; UINT32 fitOffset; findFitRecursive(index, fitIndex, fitOffset); - + // FIT not found if (!fitIndex.isValid()) return U_SUCCESS; - + // Explicitly set the item containing FIT as fixed model->setFixed(fitIndex, true); - + // Special case of FIT header UByteArray fitBody = model->body(fitIndex); const FIT_ENTRY* fitHeader = (const FIT_ENTRY*)(fitBody.constData() + fitOffset); - + // Check FIT checksum, if present UINT32 fitSize = fitHeader->Size * sizeof(FIT_ENTRY); if (fitHeader->CsFlag) { @@ -3719,13 +3719,13 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) msg(usprintf("%s: invalid FIT table checksum %02Xh, should be %02Xh", __FUNCTION__, fitHeader->Checksum, calculated), fitIndex); } } - + // Check fit header type if (fitHeader->Type != FIT_TYPE_HEADER) { msg(usprintf("%s: invalid FIT header type", __FUNCTION__), fitIndex); return U_INVALID_FIT; } - + // Add FIT header std::vector currentStrings; currentStrings.push_back(UString("_FIT_ ")); @@ -3735,7 +3735,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) currentStrings.push_back(fitEntryTypeToUString(fitHeader->Type)); currentStrings.push_back(UString()); // Empty info for FIT header fitTable.push_back(std::pair, UModelIndex>(currentStrings, fitIndex)); - + // Process all other entries UModelIndex acmIndex; UModelIndex kmIndex; @@ -3746,22 +3746,22 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) UModelIndex itemIndex; const FIT_ENTRY* currentEntry = fitHeader + i; UINT32 currentEntrySize = currentEntry->Size; - + // Check sanity if (currentEntry->Type == FIT_TYPE_HEADER) { msg(usprintf("%s: second FIT header found, the table is damaged", __FUNCTION__), fitIndex); return U_INVALID_FIT; } - + // Special case of version 0 entries if (currentEntry->Version == 0) { const FIT_ENTRY_VERSION_0_CONFIG_POLICY* policy = (const FIT_ENTRY_VERSION_0_CONFIG_POLICY*)currentEntry; info += usprintf("Index: %04Xh BitPosition: %02Xh AccessWidth: %02Xh DataRegAddr: %04Xh IndexRegAddr: %04Xh", - policy->Index, - policy->BitPosition, - policy->AccessWidth, - policy->DataRegisterAddress, - policy->IndexRegisterAddress); + policy->Index, + policy->BitPosition, + policy->AccessWidth, + policy->DataRegisterAddress, + policy->IndexRegisterAddress); } else if (currentEntry->Address > addressDiff && currentEntry->Address < 0xFFFFFFFFUL) { // Only elements in the image need to be parsed UINT32 currentEntryBase = (UINT32)(currentEntry->Address - addressDiff); @@ -3770,33 +3770,33 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) USTATUS status = U_INVALID_FIT; UByteArray item = model->header(itemIndex) + model->body(itemIndex) + model->tail(itemIndex); UINT32 localOffset = currentEntryBase - model->base(itemIndex); - + switch (currentEntry->Type) { - case FIT_TYPE_MICROCODE: - status = parseFitEntryMicrocode(item, localOffset, itemIndex, info, currentEntrySize); - break; - - case FIT_TYPE_BIOS_AC_MODULE: - status = parseFitEntryAcm(item, localOffset, itemIndex, info, currentEntrySize); - acmIndex = itemIndex; - break; - - case FIT_TYPE_AC_KEY_MANIFEST: - status = parseFitEntryBootGuardKeyManifest(item, localOffset, itemIndex, info, currentEntrySize); - kmIndex = itemIndex; - break; - - case FIT_TYPE_AC_BOOT_POLICY: - status = parseFitEntryBootGuardBootPolicy(item, localOffset, itemIndex, info, currentEntrySize); - bpIndex = itemIndex; - break; - - default: - // Do nothing - status = U_SUCCESS; - break; + case FIT_TYPE_MICROCODE: + status = parseFitEntryMicrocode(item, localOffset, itemIndex, info, currentEntrySize); + break; + + case FIT_TYPE_BIOS_AC_MODULE: + status = parseFitEntryAcm(item, localOffset, itemIndex, info, currentEntrySize); + acmIndex = itemIndex; + break; + + case FIT_TYPE_AC_KEY_MANIFEST: + status = parseFitEntryBootGuardKeyManifest(item, localOffset, itemIndex, info, currentEntrySize); + kmIndex = itemIndex; + break; + + case FIT_TYPE_AC_BOOT_POLICY: + status = parseFitEntryBootGuardBootPolicy(item, localOffset, itemIndex, info, currentEntrySize); + bpIndex = itemIndex; + break; + + default: + // Do nothing + status = U_SUCCESS; + break; } - + if (status != U_SUCCESS) itemIndex = UModelIndex(); } @@ -3804,13 +3804,13 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) msg(usprintf("%s: FIT entry #%d not found in the image", __FUNCTION__, i), fitIndex); } } - + if (itemIndex.isValid()) { // Explicitly set the item referenced by FIT as fixed // TODO: lift this restriction after FIT builder is ready model->setFixed(itemIndex, true); } - + // Add entry to fitTable currentStrings.push_back(usprintf("%016" PRIX64 "h", currentEntry->Address)); currentStrings.push_back(usprintf("%08Xh", currentEntrySize)); @@ -3820,7 +3820,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) currentStrings.push_back(info); fitTable.push_back(std::pair, UModelIndex>(currentStrings, itemIndex)); } - + // Perform validation of BootGuard stuff if (bgAcmFound) { if (!bgKeyManifestFound) { @@ -3837,7 +3837,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index) } } } - + return U_SUCCESS; } @@ -3847,24 +3847,24 @@ void FfsParser::findFitRecursive(const UModelIndex & index, UModelIndex & found, if (!index.isValid()) { return; } - + // Process child items for (int i = 0; i < model->rowCount(index); i++) { findFitRecursive(index.model()->index(i, 0, index), found, fitOffset); - + if (found.isValid()) return; } - + // Check for all FIT signatures in item's body UByteArray lastVtfBody = model->body(lastVtf); UINT32 storedFitAddress = *(const UINT32*)(lastVtfBody.constData() + lastVtfBody.size() - FIT_POINTER_OFFSET); for (INT32 offset = (INT32)model->body(index).indexOf(FIT_SIGNATURE); - offset >= 0; - offset = (INT32)model->body(index).indexOf(FIT_SIGNATURE, offset + 1)) { + offset >= 0; + offset = (INT32)model->body(index).indexOf(FIT_SIGNATURE, offset + 1)) { // FIT candidate found, calculate its physical address UINT32 fitAddress = (UINT32)(model->base(index) + (UINT32)addressDiff + model->header(index).size() + (UINT32)offset); - + // Check FIT address to be stored in the last VTF if (fitAddress == storedFitAddress) { found = index; @@ -3883,16 +3883,16 @@ USTATUS FfsParser::parseFitEntryMicrocode(const UByteArray & microcode, const UI if ((UINT32)microcode.size() - localOffset < sizeof(INTEL_MICROCODE_HEADER)) { return U_INVALID_MICROCODE; } - + const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)(microcode.constData() + localOffset); if (!microcodeHeaderValid(ucodeHeader)) { return U_INVALID_MICROCODE; } - + if ((UINT32)microcode.size() - localOffset < ucodeHeader->TotalSize) { return U_INVALID_MICROCODE; } - + // Valid microcode found info = usprintf("CpuSignature: %08Xh, Revision: %08Xh, Date: %02X.%02X.%04X", ucodeHeader->ProcessorSignature, @@ -3909,17 +3909,17 @@ USTATUS FfsParser::parseFitEntryAcm(const UByteArray & acm, const UINT32 localOf if ((UINT32)acm.size() < localOffset + sizeof(INTEL_ACM_HEADER)) { return U_INVALID_ACM; } - + const INTEL_ACM_HEADER* header = (const INTEL_ACM_HEADER*)(acm.constData() + localOffset); if (header->ModuleType != INTEL_ACM_MODULE_TYPE || header->ModuleVendor != INTEL_ACM_MODULE_VENDOR) { return U_INVALID_ACM; } - + UINT32 acmSize = header->ModuleSize * sizeof(UINT32); if ((UINT32)acm.size() < localOffset + acmSize) { return U_INVALID_ACM; } - + // Valid ACM found info = usprintf("LocalOffset: %08Xh, EntryPoint: %08Xh, ACM SVN: %04Xh, Date: %02X.%02X.%04X", localOffset, @@ -3930,7 +3930,7 @@ USTATUS FfsParser::parseFitEntryAcm(const UByteArray & acm, const UINT32 localOf header->DateYear ); realSize = acmSize; - + // Add ACM header info UString acmInfo; acmInfo += usprintf(" found at base %Xh\n" @@ -3975,7 +3975,7 @@ USTATUS FfsParser::parseFitEntryAcm(const UByteArray & acm, const UINT32 localOf acmInfo += usprintf("%02X", header->RsaSig[i]); } acmInfo += UString("\n------------------------------------------------------------------------\n\n"); - + if(header->ModuleSubtype == INTEL_ACM_MODULE_SUBTYPE_TXT_ACM) securityInfo += "TXT ACM" + acmInfo; else if(header->ModuleSubtype == INTEL_ACM_MODULE_SUBTYPE_S_ACM) @@ -3984,7 +3984,7 @@ USTATUS FfsParser::parseFitEntryAcm(const UByteArray & acm, const UINT32 localOf securityInfo += "BootGuard ACM" + acmInfo; else securityInfo += "Intel ACM" + acmInfo; - + bgAcmFound = true; return U_SUCCESS; } @@ -3995,12 +3995,12 @@ USTATUS FfsParser::parseFitEntryBootGuardKeyManifest(const UByteArray & keyManif if ((UINT32)keyManifest.size() < localOffset + sizeof(BG_KEY_MANIFEST)) { return U_INVALID_BG_KEY_MANIFEST; } - + const BG_KEY_MANIFEST* header = (const BG_KEY_MANIFEST*)(keyManifest.constData() + localOffset); if (header->Tag != BG_KEY_MANIFEST_TAG) { return U_INVALID_BG_KEY_MANIFEST; } - + // Valid KM found info = usprintf("LocalOffset: %08Xh, KM Version: %02Xh, KM SVN: %02Xh, KM ID: %02Xh", localOffset, @@ -4008,7 +4008,7 @@ USTATUS FfsParser::parseFitEntryBootGuardKeyManifest(const UByteArray & keyManif header->KmSvn, header->KmId ); - + // Add KM header info securityInfo += usprintf("Intel BootGuard Key manifest found at base %Xh\n" "Tag: __KEYM__ Version: %02Xh KmVersion: %02Xh KmSvn: %02Xh KmId: %02Xh", @@ -4018,7 +4018,7 @@ USTATUS FfsParser::parseFitEntryBootGuardKeyManifest(const UByteArray & keyManif header->KmSvn, header->KmId ); - + // Add hash of Key Manifest PubKey, this hash will be written to FPFs UINT8 hash[SHA256_DIGEST_SIZE]; sha256(&header->KeyManifestSignature.PubKey.Modulus, sizeof(header->KeyManifestSignature.PubKey.Modulus), hash); @@ -4026,17 +4026,17 @@ USTATUS FfsParser::parseFitEntryBootGuardKeyManifest(const UByteArray & keyManif for (UINT8 i = 0; i < sizeof(hash); i++) { securityInfo += usprintf("%02X", hash[i]); } - + // Add BpKeyHash securityInfo += UString("\n\nBoot Policy RSA Public Key Hash:\n"); for (UINT8 i = 0; i < sizeof(header->BpKeyHash.HashBuffer); i++) { securityInfo += usprintf("%02X", header->BpKeyHash.HashBuffer[i]); } bgKmHash = UByteArray((const char*)header->BpKeyHash.HashBuffer, sizeof(header->BpKeyHash.HashBuffer)); - + // Add Key Manifest PubKey securityInfo += usprintf("\n\nKey Manifest RSA Public Key (Exponent: %Xh):", - header->KeyManifestSignature.PubKey.Exponent); + header->KeyManifestSignature.PubKey.Exponent); for (UINT16 i = 0; i < sizeof(header->KeyManifestSignature.PubKey.Modulus); i++) { if (i % 32 == 0) securityInfo += UString("\n"); @@ -4060,7 +4060,7 @@ USTATUS FfsParser::findNextBootGuardBootPolicyElement(const UByteArray & bootPol if (dataSize < sizeof(UINT64)) { return U_ELEMENTS_NOT_FOUND; } - + UINT32 offset = elementOffset; for (; offset < dataSize - sizeof(UINT64); offset++) { const UINT64* currentPos = (const UINT64*)(bootPolicy.constData() + offset); @@ -4088,7 +4088,7 @@ USTATUS FfsParser::findNextBootGuardBootPolicyElement(const UByteArray & bootPol return U_SUCCESS; } } - + return U_ELEMENTS_NOT_FOUND; } @@ -4098,38 +4098,38 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic if ((UINT32)bootPolicy.size() < localOffset + sizeof(BG_BOOT_POLICY_MANIFEST_HEADER)) { return U_INVALID_BG_BOOT_POLICY; } - + const BG_BOOT_POLICY_MANIFEST_HEADER* header = (const BG_BOOT_POLICY_MANIFEST_HEADER*)(bootPolicy.constData() + localOffset); if (header->Tag != BG_BOOT_POLICY_MANIFEST_HEADER_TAG) { return U_INVALID_BG_BOOT_POLICY; } - + UINT32 bmSize = sizeof(BG_BOOT_POLICY_MANIFEST_HEADER); if ((UINT32)bootPolicy.size() < localOffset + bmSize) { return U_INVALID_BG_BOOT_POLICY; } - + // Valid BPM found info = usprintf("LocalOffset: %08Xh, BP SVN: %02Xh, ACM SVN: %02Xh", localOffset, header->BPSVN, header->ACMSVN ); - + // Add BP header info securityInfo += usprintf( - "Intel BootGuard Boot Policy Manifest found at base %Xh\n" - "Tag: __ACBP__ Version: %02Xh HeaderVersion: %02Xh\n" - "PMBPMVersion: %02Xh PBSVN: %02Xh ACMSVN: %02Xh NEMDataStack: %04Xh\n", - model->base(parent) + localOffset, - header->Version, - header->HeaderVersion, - header->PMBPMVersion, - header->BPSVN, - header->ACMSVN, - header->NEMDataSize - ); - + "Intel BootGuard Boot Policy Manifest found at base %Xh\n" + "Tag: __ACBP__ Version: %02Xh HeaderVersion: %02Xh\n" + "PMBPMVersion: %02Xh PBSVN: %02Xh ACMSVN: %02Xh NEMDataStack: %04Xh\n", + model->base(parent) + localOffset, + header->Version, + header->HeaderVersion, + header->PMBPMVersion, + header->BPSVN, + header->ACMSVN, + header->NEMDataSize + ); + // Iterate over elements to get them all UINT32 elementOffset = 0; UINT32 elementSize = 0; @@ -4140,27 +4140,27 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic const BG_IBB_ELEMENT* elementHeader = (const BG_IBB_ELEMENT*)currentPos; // Valid IBB element found securityInfo += usprintf( - "\nInitial Boot Block Element found at base %Xh\n" - "Tag: __IBBS__ Version: %02Xh Unknown: %02Xh\n" - "Flags: %08Xh IbbMchBar: %08llXh VtdBar: %08llXh\n" - "PmrlBase: %08Xh PmrlLimit: %08Xh EntryPoint: %08Xh", - model->base(parent) + localOffset + elementOffset, - elementHeader->Version, - elementHeader->Unknown, - elementHeader->Flags, - (unsigned long long)elementHeader->IbbMchBar, - (unsigned long long)elementHeader->VtdBar, - elementHeader->PmrlBase, - elementHeader->PmrlLimit, - elementHeader->EntryPoint - ); - + "\nInitial Boot Block Element found at base %Xh\n" + "Tag: __IBBS__ Version: %02Xh Unknown: %02Xh\n" + "Flags: %08Xh IbbMchBar: %08llXh VtdBar: %08llXh\n" + "PmrlBase: %08Xh PmrlLimit: %08Xh EntryPoint: %08Xh", + model->base(parent) + localOffset + elementOffset, + elementHeader->Version, + elementHeader->Unknown, + elementHeader->Flags, + (unsigned long long)elementHeader->IbbMchBar, + (unsigned long long)elementHeader->VtdBar, + elementHeader->PmrlBase, + elementHeader->PmrlLimit, + elementHeader->EntryPoint + ); + // Add PostIbbHash securityInfo += UString("\n\nPost IBB Hash:\n"); for (UINT8 i = 0; i < sizeof(elementHeader->IbbHash.HashBuffer); i++) { securityInfo += usprintf("%02X", elementHeader->IbbHash.HashBuffer[i]); } - + // Check for non-empry PostIbbHash UByteArray postIbbHash((const char*)elementHeader->IbbHash.HashBuffer, sizeof(elementHeader->IbbHash.HashBuffer)); if (postIbbHash.count('\x00') != postIbbHash.size() && postIbbHash.count('\xFF') != postIbbHash.size()) { @@ -4169,20 +4169,20 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic range.Hash = postIbbHash; bgProtectedRanges.push_back(range); } - + // Add Digest bgBpDigest = UByteArray((const char*)elementHeader->Digest.HashBuffer, sizeof(elementHeader->Digest.HashBuffer)); securityInfo += UString("\n\nIBB Digest:\n"); for (UINT8 i = 0; i < (UINT8)bgBpDigest.size(); i++) { securityInfo += usprintf("%02X", (UINT8)bgBpDigest.at(i)); } - + // Add all IBB segments securityInfo += UString("\n\nIBB Segments:\n"); const BG_IBB_SEGMENT_ELEMENT* segments = (const BG_IBB_SEGMENT_ELEMENT*)(elementHeader + 1); for (UINT8 i = 0; i < elementHeader->IbbSegCount; i++) { securityInfo += usprintf("Flags: %04Xh Address: %08Xh Size: %08Xh\n", - segments[i].Flags, segments[i].Base, segments[i].Size); + segments[i].Flags, segments[i].Base, segments[i].Size); if (segments[i].Flags == BG_IBB_SEGMENT_FLAG_IBB) { BG_PROTECTED_RANGE range = {}; range.Offset = segments[i].Base; @@ -4195,12 +4195,12 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic else if (*currentPos == BG_BOOT_POLICY_MANIFEST_PLATFORM_MANUFACTURER_ELEMENT_TAG) { const BG_PLATFORM_MANUFACTURER_ELEMENT* elementHeader = (const BG_PLATFORM_MANUFACTURER_ELEMENT*)currentPos; securityInfo += usprintf( - "\nPlatform Manufacturer Data Element found at base %Xh\n" - "Tag: __PMDA__ Version: %02Xh DataSize: %02Xh", - model->base(parent) + localOffset + elementOffset, - elementHeader->Version, - elementHeader->DataSize - ); + "\nPlatform Manufacturer Data Element found at base %Xh\n" + "Tag: __PMDA__ Version: %02Xh DataSize: %02Xh", + model->base(parent) + localOffset + elementOffset, + elementHeader->Version, + elementHeader->DataSize + ); // Check for Microsoft PMDA hash data const BG_MICROSOFT_PMDA_HEADER* pmdaHeader = (const BG_MICROSOFT_PMDA_HEADER*)(elementHeader + 1); if (pmdaHeader->Version == BG_MICROSOFT_PMDA_VERSION @@ -4209,14 +4209,14 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic securityInfo += UString("\nMicrosoft PMDA-based protected ranges:\n"); const BG_MICROSOFT_PMDA_ENTRY* entries = (const BG_MICROSOFT_PMDA_ENTRY*)(pmdaHeader + 1); for (UINT32 i = 0; i < pmdaHeader->NumEntries; i++) { - + securityInfo += usprintf("Address: %08Xh Size: %08Xh\n", entries[i].Address, entries[i].Size); securityInfo += UString("Hash: "); for (UINT8 j = 0; j < sizeof(entries[i].Hash); j++) { securityInfo += usprintf("%02X", entries[i].Hash[j]); } securityInfo += UString("\n"); - + BG_PROTECTED_RANGE range = {}; range.Offset = entries[i].Address; range.Size = entries[i].Size; @@ -4239,12 +4239,12 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic else if (*currentPos == BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT_TAG) { const BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT* elementHeader = (const BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT*)currentPos; securityInfo += usprintf( - "\nBoot Policy Signature Element found at base %Xh\n" - "Tag: __PMSG__ Version: %02Xh", - model->base(parent) + localOffset + elementOffset, - elementHeader->Version - ); - + "\nBoot Policy Signature Element found at base %Xh\n" + "Tag: __PMSG__ Version: %02Xh", + model->base(parent) + localOffset + elementOffset, + elementHeader->Version + ); + // Add PubKey securityInfo += usprintf("\n\nBoot Policy RSA Public Key (Exponent: %Xh):", elementHeader->KeySignature.PubKey.Exponent); for (UINT16 i = 0; i < sizeof(elementHeader->KeySignature.PubKey.Modulus); i++) { @@ -4252,7 +4252,7 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic securityInfo += UString("\n"); securityInfo += usprintf("%02X", elementHeader->KeySignature.PubKey.Modulus[i]); } - + // Calculate and add PubKey hash UINT8 hash[SHA256_DIGEST_SIZE]; sha256(&elementHeader->KeySignature.PubKey.Modulus, sizeof(elementHeader->KeySignature.PubKey.Modulus), hash); @@ -4263,7 +4263,7 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic securityInfo += usprintf("%02X", hash[i]); } bgBpHash = UByteArray((const char*)hash, sizeof(hash)); - + // Add Signature securityInfo += UString("\n\nBoot Policy RSA Signature:"); for (UINT16 i = 0; i < sizeof(elementHeader->KeySignature.Signature.Signature); i++) { @@ -4274,7 +4274,7 @@ USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic } status = findNextBootGuardBootPolicyElement(bootPolicy, elementOffset + elementSize, elementOffset, elementSize); } - + securityInfo += UString("\n------------------------------------------------------------------------\n\n"); bgBootPolicyFound = true; return U_SUCCESS; @@ -4287,12 +4287,12 @@ USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index) const UINT32 bodySize = (UINT32)model->body(index).size(); UINT32 offset = 0; USTATUS result = U_SUCCESS; - + while(true) { // Parse current microcode UModelIndex currentMicrocode; UByteArray ucode = model->body(index).mid(offset); - + // Check for empty area if (ucode.size() == ucode.count('\xFF') || ucode.size() == ucode.count('\x00')) { result = U_INVALID_MICROCODE; @@ -4300,20 +4300,20 @@ USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index) else { result = parseIntelMicrocodeHeader(ucode, headerSize + offset, index, currentMicrocode); } - + // Add the rest as padding if (result) { if (offset < bodySize) { // Get info UString name = UString("Padding"); - UString info = usprintf("Full size: %Xh (%u)", ucode.size(), ucode.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)ucode.size(), (UINT32)ucode.size()); + // Add tree item model->addItem(headerSize + offset, Types::Padding, getPaddingType(ucode), name, UString(), info, UByteArray(), ucode, UByteArray(), Fixed, index); } return U_SUCCESS; } - + // Get to next candidate offset += model->header(currentMicrocode).size() + model->body(currentMicrocode).size() + model->tail(currentMicrocode).size(); if (offset >= bodySize) @@ -4328,52 +4328,52 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const if ((UINT32)microcode.size() < sizeof(INTEL_MICROCODE_HEADER)) { return U_INVALID_MICROCODE; } - + const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)microcode.constData(); - + if (!microcodeHeaderValid(ucodeHeader)) { return U_INVALID_MICROCODE; } - + // We have enough data to fit the whole TotalSize if ((UINT32)microcode.size() < ucodeHeader->TotalSize) { return U_INVALID_MICROCODE; } - + // Valid microcode found UINT32 dataSize = ucodeHeader->DataSize; if (dataSize == 0) { dataSize = INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO; } - + // Cross check DataSize and TotalSize if (ucodeHeader->TotalSize < sizeof(INTEL_MICROCODE_HEADER) + dataSize) { return U_INVALID_MICROCODE; } - + // Recalculate the whole microcode checksum UByteArray tempMicrocode = microcode; INTEL_MICROCODE_HEADER* tempUcodeHeader = (INTEL_MICROCODE_HEADER*)(tempMicrocode.data()); tempUcodeHeader->Checksum = 0; UINT32 calculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), tempUcodeHeader->TotalSize); bool msgInvalidChecksum = (ucodeHeader->Checksum != calculated); - + // Construct header, body and tail UByteArray header = microcode.left(sizeof(INTEL_MICROCODE_HEADER)); UByteArray body = microcode.mid(sizeof(INTEL_MICROCODE_HEADER), dataSize); UByteArray tail; - + // Check if the tail is present if (ucodeHeader->TotalSize > sizeof(INTEL_MICROCODE_HEADER) + dataSize) { tail = microcode.mid(sizeof(INTEL_MICROCODE_HEADER) + dataSize, ucodeHeader->TotalSize - (sizeof(INTEL_MICROCODE_HEADER) + dataSize)); } - + // Check if we have extended header in the tail UString extendedHeaderInfo; bool msgUnknownOrDamagedMicrocodeTail = false; if ((UINT32)tail.size() >= sizeof(INTEL_MICROCODE_EXTENDED_HEADER)) { const INTEL_MICROCODE_EXTENDED_HEADER* extendedHeader = (const INTEL_MICROCODE_EXTENDED_HEADER*)tail.constData(); - + // Reserved bytes are all zeroes bool extendedReservedBytesValid = true; for (UINT8 i = 0; i < sizeof(extendedHeader->Reserved); i++) { @@ -4382,7 +4382,7 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const break; } } - + // We have more than 0 entries and they are all in the tail if (extendedReservedBytesValid && extendedHeader->EntryCount > 0 @@ -4391,27 +4391,27 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const INTEL_MICROCODE_EXTENDED_HEADER* tempExtendedHeader = (INTEL_MICROCODE_EXTENDED_HEADER*)(tempMicrocode.data() + sizeof(INTEL_MICROCODE_HEADER) + dataSize); tempExtendedHeader->Checksum = 0; UINT32 extendedCalculated = calculateChecksum32((const UINT32*)tempExtendedHeader, sizeof(INTEL_MICROCODE_EXTENDED_HEADER) + extendedHeader->EntryCount * sizeof(INTEL_MICROCODE_EXTENDED_HEADER_ENTRY)); - + extendedHeaderInfo = usprintf("\nExtended header entries: %u\nExtended header checksum: %08Xh, ", extendedHeader->EntryCount, extendedHeader->Checksum) - + (extendedHeader->Checksum == extendedCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", extendedCalculated)); - + + (extendedHeader->Checksum == extendedCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", extendedCalculated)); + const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY* firstEntry = (const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY*)(extendedHeader + 1); for (UINT8 i = 0; i < extendedHeader->EntryCount; i++) { const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY* entry = (const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY*)(firstEntry + i); - + // Recalculate checksum after patching tempUcodeHeader->Checksum = 0; tempUcodeHeader->ProcessorFlags = entry->ProcessorFlags; tempUcodeHeader->ProcessorSignature = entry->ProcessorSignature; UINT32 entryCalculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), sizeof(INTEL_MICROCODE_HEADER) + dataSize); - + extendedHeaderInfo += usprintf("\nCPU signature #%u: %08Xh\nCPU flags #%u: %02Xh\nChecksum #%u: %08Xh, ", i + 1, entry->ProcessorSignature, i + 1, entry->ProcessorFlags, i + 1, entry->Checksum) - + (entry->Checksum == entryCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", entryCalculated)); + + (entry->Checksum == entryCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", entryCalculated)); } } else { @@ -4421,16 +4421,16 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const else if (tail.size() != 0) { msgUnknownOrDamagedMicrocodeTail = true; } - + // Get microcode binary UByteArray microcodeBinary = microcode.left(ucodeHeader->TotalSize); - + // Add info UString name("Intel microcode"); UString info = usprintf("Full size: %Xh (%u)\nHeader size: 0h (0u)\nBody size: %Xh (%u)\nTail size: 0h (0u)\n" "Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nCPU flags: %02Xh\nChecksum: %08Xh, ", - microcodeBinary.size(), microcodeBinary.size(), - microcodeBinary.size(), microcodeBinary.size(), + (UINT32)microcodeBinary.size(), (UINT32)microcodeBinary.size(), + (UINT32)microcodeBinary.size(), (UINT32)microcodeBinary.size(), ucodeHeader->DateDay, ucodeHeader->DateMonth, ucodeHeader->DateYear, @@ -4438,16 +4438,16 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const ucodeHeader->UpdateRevision, ucodeHeader->ProcessorFlags, ucodeHeader->Checksum) - + (ucodeHeader->Checksum == calculated ? UString("valid") : usprintf("invalid, should be %08Xh", calculated)) - + extendedHeaderInfo; - + + (ucodeHeader->Checksum == calculated ? UString("valid") : usprintf("invalid, should be %08Xh", calculated)) + + extendedHeaderInfo; + // Add tree item index = model->addItem(localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, UByteArray(), microcodeBinary, UByteArray(), Fixed, parent); if (msgInvalidChecksum) msg(usprintf("%s: invalid microcode checksum %08Xh, should be %08Xh", __FUNCTION__, ucodeHeader->Checksum, calculated), index); if (msgUnknownOrDamagedMicrocodeTail) - msg(usprintf("%s: extended header of size %Xh (%u) found, but it's damaged or has unknown format", __FUNCTION__, tail.size(), tail.size()), index); - + msg(usprintf("%s: extended header of size %Xh (%u) found, but it's damaged or has unknown format", __FUNCTION__, (UINT32)tail.size(), (UINT32)tail.size()), index); + // No need to parse the body further for now return U_SUCCESS; } @@ -4455,16 +4455,16 @@ USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 localOffset, const UINT32 sbpdtOffsetFixup, const UModelIndex & parent, UModelIndex & index) { UINT32 regionSize = (UINT32)region.size(); - + // Check region size if (regionSize < sizeof(BPDT_HEADER)) { msg(usprintf("%s: BPDT region too small to fit BPDT partition table header", __FUNCTION__), parent); return U_INVALID_ME_PARTITION_TABLE; } - + // Populate partition table header const BPDT_HEADER* ptHeader = (const BPDT_HEADER*)(region.constData()); - + // Check region size again UINT32 ptBodySize = ptHeader->NumEntries * sizeof(BPDT_ENTRY); UINT32 ptSize = sizeof(BPDT_HEADER) + ptBodySize; @@ -4472,28 +4472,28 @@ USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 local msg(usprintf("%s: BPDT region too small to fit BPDT partition table", __FUNCTION__), parent); return U_INVALID_ME_PARTITION_TABLE; } - + // Get info UByteArray header = region.left(sizeof(BPDT_HEADER)); UByteArray body = region.mid(sizeof(BPDT_HEADER), ptBodySize); - + UString name = UString("BPDT partition table"); UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u\nVersion: %2Xh\n" "IFWI version: %Xh\nFITC version: %u.%u.%u.%u", ptSize, ptSize, - header.size(), header.size(), + (UINT32)header.size(), (UINT32)header.size(), ptBodySize, ptBodySize, ptHeader->NumEntries, ptHeader->HeaderVersion, ptHeader->IfwiVersion, ptHeader->FitcMajor, ptHeader->FitcMinor, ptHeader->FitcHotfix, ptHeader->FitcBuild); - + // Add tree item index = model->addItem(localOffset, Types::BpdtStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + // Adjust offset UINT32 offset = sizeof(BPDT_HEADER); - + // Add partition table entries std::vector partitions; const BPDT_ENTRY* firstPtEntry = (const BPDT_ENTRY*)((const UINT8*)ptHeader + sizeof(BPDT_HEADER)); @@ -4501,7 +4501,7 @@ USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 local for (UINT16 i = 0; i < numEntries; i++) { // Populate entry header const BPDT_ENTRY* ptEntry = firstPtEntry + i; - + // Get info name = bpdtEntryTypeToUString(ptEntry->Type); info = usprintf("Full size: %lXh (%lu)\nType: %Xh\nPartition offset: %Xh\nPartition length: %Xh", @@ -4513,13 +4513,13 @@ USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 local UString("\nSplit sub-partition second part: ") + (ptEntry->SplitSubPartitionSecondPart ? "Yes" : "No") + UString("\nCode sub-partition: ") + (ptEntry->CodeSubPartition ? "Yes" : "No") + UString("\nUMA cachable: ") + (ptEntry->UmaCachable ? "Yes" : "No"); - + // Add tree item UModelIndex entryIndex = model->addItem(localOffset + offset, Types::BpdtEntry, 0, name, UString(), info, UByteArray(), UByteArray((const char*)ptEntry, sizeof(BPDT_ENTRY)), UByteArray(), Fixed, index); - + // Adjust offset offset += sizeof(BPDT_ENTRY); - + if (ptEntry->Offset != 0 && ptEntry->Offset != 0xFFFFFFFF && ptEntry->Size != 0) { // Add to partitions vector BPDT_PARTITION_INFO partition = {}; @@ -4530,28 +4530,28 @@ USTATUS FfsParser::parseBpdtRegion(const UByteArray & region, const UINT32 local partitions.push_back(partition); } } - + // Add padding if there's no partions to add if (partitions.size() == 0) { UByteArray partition = region.mid(ptSize); - + // Get info name = UString("Padding"); info = usprintf("Full size: %Xh (%u)", - partition.size(), partition.size()); - + (UINT32)partition.size(), (UINT32)partition.size()); + // Add tree item model->addItem(localOffset + ptSize, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); return U_SUCCESS; } - + make_partition_table_consistent: // Sort partitions by offset std::sort(partitions.begin(), partitions.end()); - + // Check for intersections and paddings between partitions BPDT_PARTITION_INFO padding = {}; - + // Check intersection with the partition table header if (partitions.front().ptEntry.Offset < ptSize) { msg(usprintf("%s: BPDT partition has intersection with BPDT partition table, skipped", __FUNCTION__), @@ -4569,7 +4569,7 @@ make_partition_table_consistent: // Check for intersections/paddings between partitions for (size_t i = 1; i < partitions.size(); i++) { UINT32 previousPartitionEnd = partitions[i - 1].ptEntry.Offset + partitions[i - 1].ptEntry.Size; - + // Check that partition is fully present in the image if ((UINT64)partitions[i].ptEntry.Offset + (UINT64)partitions[i].ptEntry.Size > regionSize) { if ((UINT64)partitions[i].ptEntry.Offset >= (UINT64)region.size()) { @@ -4582,7 +4582,7 @@ make_partition_table_consistent: partitions[i].ptEntry.Size = regionSize - (UINT32)partitions[i].ptEntry.Offset; } } - + // Check for intersection with previous partition if (partitions[i].ptEntry.Offset < previousPartitionEnd) { // Check if current partition is located inside previous one @@ -4599,7 +4599,7 @@ make_partition_table_consistent: goto make_partition_table_consistent; } } - + // Check for padding between current and previous partitions else if (partitions[i].ptEntry.Offset > previousPartitionEnd) { padding.ptEntry.Offset = previousPartitionEnd; @@ -4610,7 +4610,7 @@ make_partition_table_consistent: partitions.insert(iter, padding); } } - + // Partition map is consistent for (size_t i = 0; i < partitions.size(); i++) { if (partitions[i].type == Types::BpdtPartition) { @@ -4618,33 +4618,33 @@ make_partition_table_consistent: UString name = bpdtEntryTypeToUString(partitions[i].ptEntry.Type); UByteArray partition = region.mid(partitions[i].ptEntry.Offset, partitions[i].ptEntry.Size); UByteArray signature = partition.left(sizeof(UINT32)); - + UString info = usprintf("Full size: %Xh (%u)\nType: %Xh", - partition.size(), partition.size(), + (UINT32)partition.size(), (UINT32)partition.size(), partitions[i].ptEntry.Type) + UString("\nSplit sub-partition first part: ") + (partitions[i].ptEntry.SplitSubPartitionFirstPart ? "Yes" : "No") + UString("\nSplit sub-partition second part: ") + (partitions[i].ptEntry.SplitSubPartitionSecondPart ? "Yes" : "No") + UString("\nCode sub-partition: ") + (partitions[i].ptEntry.CodeSubPartition ? "Yes" : "No") + UString("\nUMA cachable: ") + (partitions[i].ptEntry.UmaCachable ? "Yes" : "No"); - + UString text = bpdtEntryTypeToUString(partitions[i].ptEntry.Type); - + // Add tree item UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset, Types::BpdtPartition, 0, name, text, info, UByteArray(), partition, UByteArray(), Fixed, parent); - + // Special case of S-BPDT if (partitions[i].ptEntry.Type == BPDT_ENTRY_TYPE_SBPDT) { UModelIndex sbpdtIndex; parseBpdtRegion(partition, 0, partitions[i].ptEntry.Offset, partitionIndex, sbpdtIndex); // Third parameter is a fixup for S-BPDT offset entries, because they are calculated from the start of BIOS region } - + // Parse code partitions if (readUnaligned((const UINT32*)partition.constData()) == CPD_SIGNATURE) { // Parse code partition contents UModelIndex cpdIndex; parseCpdRegion(partition, 0, partitionIndex, cpdIndex); } - + // TODO: make this generic again if (partitions[i].ptEntry.Type > BPDT_ENTRY_TYPE_TBT && partitions[i].ptEntry.Type != BPDT_ENTRY_TYPE_USB_PHY @@ -4656,31 +4656,31 @@ make_partition_table_consistent: } else if (partitions[i].type == Types::Padding) { UByteArray padding = region.mid(partitions[i].ptEntry.Offset, partitions[i].ptEntry.Size); - + // Get info name = UString("Padding"); info = usprintf("Full size: %Xh (%u)", - padding.size(), padding.size()); - + (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item model->addItem(localOffset + partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, parent); } } - + // Add padding after the last region if ((UINT64)partitions.back().ptEntry.Offset + (UINT64)partitions.back().ptEntry.Size < regionSize) { UINT64 usedSize = (UINT64)partitions.back().ptEntry.Offset + (UINT64)partitions.back().ptEntry.Size; UByteArray padding = region.mid(partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size, (int)(regionSize - usedSize)); - + // Get info name = UString("Padding"); info = usprintf("Full size: %Xh (%u)", - padding.size(), padding.size()); - + (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item model->addItem(localOffset + partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, parent); } - + return U_SUCCESS; } @@ -4691,10 +4691,10 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO msg(usprintf("%s: CPD too small to fit rev1 partition table header", __FUNCTION__), parent); return U_INVALID_ME_PARTITION_TABLE; } - + // Populate partition table header const CPD_REV1_HEADER* cpdHeader = (const CPD_REV1_HEADER*)region.constData(); - + // Check header version to be known UINT32 ptHeaderSize = 0; if (cpdHeader->HeaderVersion == 2) { @@ -4702,13 +4702,13 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO msg(usprintf("%s: CPD too small to fit rev2 partition table header", __FUNCTION__), parent); return U_INVALID_ME_PARTITION_TABLE; } - + ptHeaderSize = sizeof(CPD_REV2_HEADER); } else if (cpdHeader->HeaderVersion == 1) { ptHeaderSize = sizeof(CPD_REV1_HEADER); } - + // Check directory size again UINT32 ptBodySize = cpdHeader->NumEntries * sizeof(CPD_ENTRY); UINT32 ptSize = ptHeaderSize + ptBodySize; @@ -4716,7 +4716,7 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO msg(usprintf("%s: CPD too small to fit the whole partition table", __FUNCTION__), parent); return U_INVALID_ME_PARTITION_TABLE; } - + // Get info UByteArray header = region.left(ptHeaderSize); UByteArray body = region.mid(ptHeaderSize, ptBodySize); @@ -4724,15 +4724,15 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u\n" "Header version: %u\nEntry version: %u", ptSize, ptSize, - header.size(), header.size(), - body.size(), body.size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), cpdHeader->NumEntries, cpdHeader->HeaderVersion, cpdHeader->EntryVersion); - + // Add tree item index = model->addItem(localOffset, Types::CpdStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + // Add partition table entries std::vector partitions; UINT32 offset = ptHeaderSize; @@ -4741,21 +4741,21 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO // Populate entry header const CPD_ENTRY* cpdEntry = firstCpdEntry + i; UByteArray entry((const char*)cpdEntry, sizeof(CPD_ENTRY)); - + // Get info name = usprintf("%.12s", cpdEntry->EntryName); info = usprintf("Full size: %Xh (%u)\nEntry offset: %Xh\nEntry length: %Xh\nHuffman compressed: ", - entry.size(), entry.size(), + (UINT32)entry.size(), (UINT32)entry.size(), cpdEntry->Offset.Offset, cpdEntry->Length) + (cpdEntry->Offset.HuffmanCompressed ? "Yes" : "No"); - + // Add tree item UModelIndex entryIndex = model->addItem(offset, Types::CpdEntry, 0, name, UString(), info, UByteArray(), entry, UByteArray(), Fixed, index); - + // Adjust offset offset += sizeof(CPD_ENTRY); - + if (cpdEntry->Offset.Offset != 0 && cpdEntry->Length != 0) { // Add to partitions vector CPD_PARTITION_INFO partition; @@ -4766,38 +4766,38 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO partitions.push_back(partition); } } - + // Add padding if there's no partions to add if (partitions.size() == 0) { UByteArray partition = region.mid(ptSize); - + // Get info name = UString("Padding"); info = usprintf("Full size: %Xh (%u)", - partition.size(), partition.size()); - + (UINT32)partition.size(), (UINT32)partition.size()); + // Add tree item model->addItem(localOffset + ptSize, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); - + return U_SUCCESS; } - + // Sort partitions by offset std::sort(partitions.begin(), partitions.end()); - + // Because lenghts for all Huffmann-compressed partitions mean nothing at all, we need to split all partitions into 2 classes: // 1. CPD manifest // 2. Metadata entries UINT32 i = 1; // manifest is index 0, .met partitions start at index 1 while (i < partitions.size()) { name = usprintf("%.12s", partitions[i].ptEntry.EntryName); - + // Check if the current entry is metadata entry if (!name.endsWith(".met")) { // No need to parse further, all metadata partitions are parsed break; } - + // Parse into data block, find Module Attributes extension, and get compressed size from there UINT32 offset = 0; UINT32 length = 0xFFFFFFFF; // Special guardian value @@ -4813,17 +4813,17 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO } else break; } - + // Search down for corresponding code partition // Construct its name by removing the .met suffix name.chop(4); - + // Search bool found = false; UINT32 j = 1; while (j < partitions.size()) { UString namej = usprintf("%.12s", partitions[j].ptEntry.EntryName); - + if (name == namej) { found = true; // Found it, update its Length if needed @@ -4845,18 +4845,18 @@ USTATUS FfsParser::parseCpdRegion(const UByteArray & region, const UINT32 localO if (!found) { msg(usprintf("%s: no code partition", __FUNCTION__), partitions[i].index); } - + // Check the next partition i++; } - + make_partition_table_consistent: // Sort partitions by offset std::sort(partitions.begin(), partitions.end()); - + // Check for intersections and paddings between partitions CPD_PARTITION_INFO padding = {}; - + // Check intersection with the partition table header if (partitions.front().ptEntry.Offset.Offset < ptSize) { msg(usprintf("%s: CPD partition has intersection with CPD partition table, skipped", __FUNCTION__), @@ -4874,7 +4874,7 @@ make_partition_table_consistent: // Check for intersections/paddings between partitions for (size_t i = 1; i < partitions.size(); i++) { UINT32 previousPartitionEnd = partitions[i - 1].ptEntry.Offset.Offset + partitions[i - 1].ptEntry.Length; - + // Check that current region is fully present in the image if ((UINT64)partitions[i].ptEntry.Offset.Offset + (UINT64)partitions[i].ptEntry.Length > (UINT64)region.size()) { if ((UINT64)partitions[i].ptEntry.Offset.Offset >= (UINT64)region.size()) { @@ -4893,7 +4893,7 @@ make_partition_table_consistent: partitions[i].ptEntry.Length = (UINT32)region.size() - (UINT32)partitions[i].ptEntry.Offset.Offset; } } - + // Check for intersection with previous partition if (partitions[i].ptEntry.Offset.Offset < previousPartitionEnd) { // Check if previous partition was compressed but did not have metadata @@ -4903,7 +4903,7 @@ make_partition_table_consistent: partitions[i - 1].ptEntry.Length = (UINT32)partitions[i].ptEntry.Offset.Offset - (UINT32)partitions[i - 1].ptEntry.Offset.Offset; goto make_partition_table_consistent; } - + // Check if current partition is located inside previous one if (partitions[i].ptEntry.Offset.Offset + partitions[i].ptEntry.Length <= previousPartitionEnd) { msg(usprintf("%s: CPD partition is located inside another CPD partition, skipped", __FUNCTION__), @@ -4935,15 +4935,15 @@ make_partition_table_consistent: padding.type = Types::Padding; partitions.push_back(padding); } - + // Partition map is consistent for (size_t i = 0; i < partitions.size(); i++) { if (partitions[i].type == Types::CpdPartition) { UByteArray partition = region.mid(partitions[i].ptEntry.Offset.Offset, partitions[i].ptEntry.Length); - + // Get info name = usprintf("%.12s", partitions[i].ptEntry.EntryName); - + // It's a manifest if (name.endsWith(".man")) { if (!partitions[i].ptEntry.Offset.HuffmanCompressed @@ -4952,13 +4952,13 @@ make_partition_table_consistent: if (manifestHeader->HeaderId == ME_MANIFEST_HEADER_ID) { UByteArray header = partition.left(manifestHeader->HeaderLength * sizeof(UINT32)); UByteArray body = partition.mid(manifestHeader->HeaderLength * sizeof(UINT32)); - + info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)" "\nHeader type: %u\nHeader length: %lXh (%lu)\nHeader version: %Xh\nFlags: %08Xh\nVendor: %Xh\n" "Date: %Xh\nSize: %lXh (%lu)\nVersion: %u.%u.%u.%u\nSecurity version number: %u\nModulus size: %lXh (%lu)\nExponent size: %lXh (%lu)", - partition.size(), partition.size(), - header.size(), header.size(), - body.size(), body.size(), + (UINT32)partition.size(), (UINT32)partition.size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), manifestHeader->HeaderType, manifestHeader->HeaderLength * sizeof(UINT32), manifestHeader->HeaderLength * sizeof(UINT32), manifestHeader->HeaderVersion, @@ -4970,10 +4970,10 @@ make_partition_table_consistent: manifestHeader->SecurityVersion, manifestHeader->ModulusSize * sizeof(UINT32), manifestHeader->ModulusSize * sizeof(UINT32), manifestHeader->ExponentSize * sizeof(UINT32), manifestHeader->ExponentSize * sizeof(UINT32)); - + // Add tree item UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::ManifestCpdPartition, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + // Parse data as extensions area parseCpdExtensionsArea(partitionIndex); } @@ -4982,42 +4982,42 @@ make_partition_table_consistent: // It's a metadata else if (name.endsWith(".met")) { info = usprintf("Full size: %Xh (%u)\nHuffman compressed: ", - partition.size(), partition.size()) + (UINT32)partition.size(), (UINT32)partition.size()) + (partitions[i].ptEntry.Offset.HuffmanCompressed ? "Yes" : "No"); - + // Calculate SHA256 hash over the metadata and add it to its info UByteArray hash(SHA256_DIGEST_SIZE, '\x00'); sha256(partition.constData(), partition.size(), hash.data()); info += UString("\nMetadata hash: ") + UString(hash.toHex().constData()); - + // Add three item UModelIndex partitionIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::MetadataCpdPartition, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); - + // Parse data as extensions area parseCpdExtensionsArea(partitionIndex); } // It's a code else { info = usprintf("Full size: %Xh (%u)\nHuffman compressed: ", - partition.size(), partition.size()) + (UINT32)partition.size(), (UINT32)partition.size()) + (partitions[i].ptEntry.Offset.HuffmanCompressed ? "Yes" : "No"); - + // Calculate SHA256 hash over the code and add it to its info UByteArray hash(SHA256_DIGEST_SIZE, '\x00'); sha256(partition.constData(), partition.size(), hash.data()); info += UString("\nHash: ") + UString(hash.toHex().constData()); - + UModelIndex codeIndex = model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::CpdPartition, Subtypes::CodeCpdPartition, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); parseRawArea(codeIndex); } } else if (partitions[i].type == Types::Padding) { UByteArray partition = region.mid(partitions[i].ptEntry.Offset.Offset, partitions[i].ptEntry.Length); - + // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size()); + // Add tree item model->addItem(localOffset + partitions[i].ptEntry.Offset.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); } @@ -5026,7 +5026,7 @@ make_partition_table_consistent: return U_INVALID_ME_PARTITION_TABLE; } } - + return U_SUCCESS; } @@ -5035,31 +5035,31 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index) if (!index.isValid()) { return U_INVALID_PARAMETER; } - + UByteArray body = model->body(index); UINT32 offset = 0; while (offset < (UINT32)body.size()) { const CPD_EXTENTION_HEADER* extHeader = (const CPD_EXTENTION_HEADER*) (body.constData() + offset); if (extHeader->Length > 0 && extHeader->Length <= ((UINT32)body.size() - offset)) { UByteArray partition = body.mid(offset, extHeader->Length); - + UString name = cpdExtensionTypeToUstring(extHeader->Type); - UString info = usprintf("Full size: %Xh (%u)\nType: %Xh", partition.size(), partition.size(), extHeader->Type); - + UString info = usprintf("Full size: %Xh (%u)\nType: %Xh", (UINT32)partition.size(), (UINT32)partition.size(), extHeader->Type); + // Parse Signed Package Info a bit further UModelIndex extIndex; if (extHeader->Type == CPD_EXT_TYPE_SIGNED_PACKAGE_INFO) { UByteArray header = partition.left(sizeof(CPD_EXT_SIGNED_PACKAGE_INFO)); UByteArray data = partition.mid(header.size()); - + const CPD_EXT_SIGNED_PACKAGE_INFO* infoHeader = (const CPD_EXT_SIGNED_PACKAGE_INFO*)header.constData(); - + info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %Xh\n" "Package name: %.4s\nVersion control number: %Xh\nSecurity version number: %Xh\n" "Usage bitmap: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - partition.size(), partition.size(), - header.size(), header.size(), - body.size(), body.size(), + (UINT32)partition.size(), (UINT32)partition.size(), + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), infoHeader->ExtensionType, infoHeader->PackageName, infoHeader->Vcn, @@ -5068,7 +5068,7 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index) infoHeader->UsageBitmap[4], infoHeader->UsageBitmap[5], infoHeader->UsageBitmap[6], infoHeader->UsageBitmap[7], infoHeader->UsageBitmap[8], infoHeader->UsageBitmap[9], infoHeader->UsageBitmap[10], infoHeader->UsageBitmap[11], infoHeader->UsageBitmap[12], infoHeader->UsageBitmap[13], infoHeader->UsageBitmap[14], infoHeader->UsageBitmap[15]); - + // Add tree item extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, header, data, UByteArray(), Fixed, index); parseSignedPackageInfoData(extIndex); @@ -5089,11 +5089,11 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index) // Need to reverse it back to normal UByteArray hash((const char*)&attrHeader->CompletePartitionHash, hashSize); std::reverse(hash.begin(), hash.end()); - + info = usprintf("Full size: %Xh (%u)\nType: %Xh\n" "Partition name: %.4s\nPartition length: %Xh\nPartition version major: %Xh\nPartition version minor: %Xh\n" "Data format version: %Xh\nInstance ID: %Xh\nHash algorithm: %Xh\nHash size: %Xh\nAction on update: %Xh", - partition.size(), partition.size(), + (UINT32)partition.size(), (UINT32)partition.size(), attrHeader->ExtensionType, attrHeader->PartitionName, attrHeader->CompletePartitionLength, @@ -5111,7 +5111,7 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index) + UString("\nAllow cross hotfix update: ") + (attrHeader->AllowCrossHotfixUpdate ? "Yes" : "No") + UString("\nPartial update only: ") + (attrHeader->PartialUpdateOnly ? "Yes" : "No") + UString("\nPartition hash: ") + UString(hash.toHex().constData()); - + // Add tree item extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index); if (msgHashSizeMismatch) { @@ -5121,22 +5121,22 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index) // Parse Module Attributes a bit further else if (extHeader->Type == CPD_EXT_TYPE_MODULE_ATTRIBUTES) { const CPD_EXT_MODULE_ATTRIBUTES* attrHeader = (const CPD_EXT_MODULE_ATTRIBUTES*)partition.constData(); - int hashSize = partition.size() - CpdExtModuleImageHashOffset; - + int hashSize = (UINT32)partition.size() - CpdExtModuleImageHashOffset; + // This hash is stored reversed // Need to reverse it back to normal UByteArray hash((const char*)attrHeader + CpdExtModuleImageHashOffset, hashSize); std::reverse(hash.begin(), hash.end()); - + info = usprintf("Full size: %Xh (%u)\nType: %Xh\n" "Compression type: %Xh\nUncompressed size: %Xh (%u)\nCompressed size: %Xh (%u)\nGlobal module ID: %Xh\nImage hash: ", - partition.size(), partition.size(), + (UINT32)partition.size(), (UINT32)partition.size(), attrHeader->ExtensionType, attrHeader->CompressionType, attrHeader->UncompressedSize, attrHeader->UncompressedSize, attrHeader->CompressedSize, attrHeader->CompressedSize, attrHeader->GlobalModuleId) + UString(hash.toHex().constData()); - + // Add tree item extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index); } @@ -5145,7 +5145,7 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index) // Add tree item, if needed extIndex = model->addItem(offset, Types::CpdExtension, 0, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, index); } - + // TODO: make this generic again if (extHeader->Type > CPD_EXT_TYPE_TBT_METADATA && extHeader->Type != CPD_EXT_TYPE_GMF_CERTIFICATE @@ -5155,13 +5155,13 @@ USTATUS FfsParser::parseCpdExtensionsArea(const UModelIndex & index) && extHeader->Type != CPD_EXT_TYPE_SPS_PLATFORM_ID) { msg(usprintf("%s: CPD extention of unknown type found", __FUNCTION__), extIndex); } - + offset += extHeader->Length; } else break; // TODO: add padding at the end } - + return U_SUCCESS; } @@ -5170,7 +5170,7 @@ USTATUS FfsParser::parseSignedPackageInfoData(const UModelIndex & index) if (!index.isValid()) { return U_INVALID_PARAMETER; } - + UByteArray body = model->body(index); UINT32 offset = 0; while (offset < (UINT32)body.size()) { @@ -5179,14 +5179,14 @@ USTATUS FfsParser::parseSignedPackageInfoData(const UModelIndex & index) // TODO: check sanity of moduleHeader->HashSize UByteArray module((const char*)moduleHeader, CpdExtSignedPkgMetadataHashOffset + moduleHeader->HashSize); UString name = usprintf("%.12s", moduleHeader->Name); - + // This hash is stored reversed // Need to reverse it back to normal UByteArray hash((const char*)moduleHeader + CpdExtSignedPkgMetadataHashOffset, moduleHeader->HashSize); std::reverse(hash.begin(), hash.end()); - + UString info = usprintf("Full size: %Xh (%u)\nType: %Xh\nHash algorithm: %Xh\nHash size: %Xh (%u)\nMetadata size: %Xh (%u)\nMetadata hash: ", - module.size(), module.size(), + (UINT32)module.size(), (UINT32)module.size(), moduleHeader->Type, moduleHeader->HashAlgorithm, moduleHeader->HashSize, moduleHeader->HashSize, @@ -5198,7 +5198,7 @@ USTATUS FfsParser::parseSignedPackageInfoData(const UModelIndex & index) else break; // TODO: add padding at the end } - + return U_SUCCESS; } @@ -5208,7 +5208,7 @@ void FfsParser::outputInfo(void) { for (size_t i = 0; i < messages.size(); i++) { std::cout << (const char *)messages[i].first.toLocal8Bit() << std::endl; } - + // Get last VTF std::vector, UModelIndex > > fitTable = getFitTable(); if (fitTable.size()) { @@ -5217,15 +5217,15 @@ void FfsParser::outputInfo(void) { std::cout << "---------------------------------------------------------------------------" << std::endl; for (size_t i = 0; i < fitTable.size(); i++) { std::cout - << (const char *)fitTable[i].first[0].toLocal8Bit() << " | " - << (const char *)fitTable[i].first[1].toLocal8Bit() << " | " - << (const char *)fitTable[i].first[2].toLocal8Bit() << " | " - << (const char *)fitTable[i].first[3].toLocal8Bit() << " | " - << (const char *)fitTable[i].first[4].toLocal8Bit() << " | " - << (const char *)fitTable[i].first[5].toLocal8Bit() << std::endl; + << (const char *)fitTable[i].first[0].toLocal8Bit() << " | " + << (const char *)fitTable[i].first[1].toLocal8Bit() << " | " + << (const char *)fitTable[i].first[2].toLocal8Bit() << " | " + << (const char *)fitTable[i].first[3].toLocal8Bit() << " | " + << (const char *)fitTable[i].first[4].toLocal8Bit() << " | " + << (const char *)fitTable[i].first[5].toLocal8Bit() << std::endl; } } - + // Get security info UString secInfo = getSecurityInfo(); if (!secInfo.isEmpty()) { diff --git a/common/ffsreport.cpp b/common/ffsreport.cpp index 8ece221..63c4128 100644 --- a/common/ffsreport.cpp +++ b/common/ffsreport.cpp @@ -1,15 +1,15 @@ /* fssreport.cpp - -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 -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + 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 + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "ffsreport.h" #include "ffs.h" @@ -25,21 +25,21 @@ std::vector FfsReport::generate() report.push_back(usprintf("%s: invalid model pointer provided", __FUNCTION__)); return report; } - + // Check root index to be valid UModelIndex root = model->index(0,0); if (!root.isValid()) { report.push_back(usprintf("%s: model root index is invalid", __FUNCTION__)); return report; } - + // Generate report recursive report.push_back(UString(" Type | Subtype | Base | Size | CRC32 | Name ")); USTATUS result = generateRecursive(report, root); if (result) { report.push_back(usprintf("%s: generateRecursive returned ", __FUNCTION__) + errorCodeToUString(result)); } - + return report; } @@ -51,27 +51,27 @@ USTATUS FfsReport::generateRecursive(std::vector & report, const UModel // Calculate item CRC32 UByteArray data = model->header(index) + model->body(index) + model->tail(index); UINT32 crc = (UINT32)crc32(0, (const UINT8*)data.constData(), (uInt)data.size()); - + // Information on current item UString text = model->text(index); UString offset = "| N/A "; if ((!model->compressed(index)) || (index.parent().isValid() && !model->compressed(index.parent()))) { offset = usprintf("| %08X ", model->base(index)); } - + report.push_back( - UString(" ") + itemTypeToUString(model->type(index)).leftJustified(16) - + UString("| ") + itemSubtypeToUString(model->type(index), model->subtype(index)).leftJustified(22) - + offset - + usprintf("| %08X | %08X | ", data.size(), crc) - + urepeated('-', level) + UString(" ") + model->name(index) + (text.isEmpty() ? UString() : UString(" | ") + text) - ); - + UString(" ") + itemTypeToUString(model->type(index)).leftJustified(16) + + UString("| ") + itemSubtypeToUString(model->type(index), model->subtype(index)).leftJustified(22) + + offset + + usprintf("| %08X | %08X | ", (UINT32)data.size(), crc) + + urepeated('-', level) + UString(" ") + model->name(index) + (text.isEmpty() ? UString() : UString(" | ") + text) + ); + // Information on child items for (int i = 0; i < model->rowCount(index); i++) { generateRecursive(report, index.model()->index(i,0,index), level + 1); } - + return U_SUCCESS; } diff --git a/common/ffsutils.cpp b/common/ffsutils.cpp index 733bfcc..698dd2b 100644 --- a/common/ffsutils.cpp +++ b/common/ffsutils.cpp @@ -1,15 +1,15 @@ /* ffsutils.cpp - -Copyright (c) 2019, LongSoft. 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2019, LongSoft. 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "ffsutils.h" #include "utility.h" @@ -21,15 +21,15 @@ USTATUS findFileRecursive(TreeModel *model, const UModelIndex index, const UStri { if (!index.isValid()) return U_SUCCESS; - + if (hexPattern.isEmpty()) return U_INVALID_PARAMETER; - + const char *hexPatternRaw = hexPattern.toLocal8Bit(); std::vector pattern, patternMask; if (!makePattern(hexPatternRaw, pattern, patternMask)) return U_INVALID_PARAMETER; - + // Check for "all substrings" pattern size_t count = 0; for (size_t i = 0; i < patternMask.size(); i++) @@ -37,12 +37,12 @@ USTATUS findFileRecursive(TreeModel *model, const UModelIndex index, const UStri count++; if (count == patternMask.size()) return U_SUCCESS; - + bool hasChildren = (model->rowCount(index) > 0); for (int i = 0; i < model->rowCount(index); i++) { findFileRecursive(model, index.model()->index(i, index.column(), index), hexPattern, mode, files); } - + UByteArray data; if (hasChildren) { if (mode == SEARCH_MODE_HEADER) @@ -58,16 +58,16 @@ USTATUS findFileRecursive(TreeModel *model, const UModelIndex index, const UStri else data = model->header(index) + model->body(index); } - + const UINT8 *rawData = reinterpret_cast(data.constData()); INTN offset = findPattern(pattern.data(), patternMask.data(), pattern.size(), rawData, data.size(), 0); - + // For patterns that cross header|body boundary, skip patterns entirely located in body, since // children search above has already found them. if (hasChildren && mode == SEARCH_MODE_ALL && offset >= model->header(index).size()) { offset = -1; } - + if (offset >= 0) { if (model->type(index) != Types::File) { UModelIndex ffs = model->findParentOfType(index, Types::File); @@ -79,9 +79,9 @@ USTATUS findFileRecursive(TreeModel *model, const UModelIndex index, const UStri else { files.insert(std::pair(index, UModelIndex())); } - + } - + return U_SUCCESS; } diff --git a/common/guiddatabase.cpp b/common/guiddatabase.cpp index 862b24d..c8aa89d 100644 --- a/common/guiddatabase.cpp +++ b/common/guiddatabase.cpp @@ -1,14 +1,14 @@ /* guiddatabase.cpp - -Copyright (c) 2017, LongSoft. 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. -*/ + + Copyright (c) 2017, LongSoft. 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. + */ #include "guiddatabase.h" #include "ubytearray.h" @@ -53,17 +53,17 @@ static std::string readGuidDatabase(const UString &path) { void initGuidDatabase(const UString & path, UINT32* numEntries) { gLocalGuidDatabase.clear(); - + std::stringstream file(readGuidDatabase(path)); - + while (!file.eof()) { std::string line; std::getline(file, line); - + // Use sharp symbol as commentary if (line.size() == 0 || line[0] == '#') continue; - + // GUID and name are comma-separated std::vector lineParts; std::string::size_type prev = 0, curr = 0; @@ -73,17 +73,17 @@ void initGuidDatabase(const UString & path, UINT32* numEntries) prev = ++curr; } lineParts.push_back(UString(line.substr(prev, curr-prev).c_str())); - + if (lineParts.size() < 2) continue; - + EFI_GUID guid; if (!ustringToGuid(lineParts[0], guid)) continue; - + gLocalGuidDatabase[guid] = lineParts[1]; } - + if (numEntries) *numEntries = (UINT32)gLocalGuidDatabase.size(); } @@ -111,19 +111,19 @@ UString guidDatabaseLookup(const EFI_GUID & guid) GuidDatabase guidDatabaseFromTreeRecursive(TreeModel * model, const UModelIndex index) { GuidDatabase db; - + if (!index.isValid()) return db; - + for (int i = 0; i < model->rowCount(index); i++) { GuidDatabase tmpDb = guidDatabaseFromTreeRecursive(model, index.model()->index(i, index.column(), index)); - + db.insert(tmpDb.begin(), tmpDb.end()); } - + if (model->type(index) == Types::File && !model->text(index).isEmpty()) db[readUnaligned((const EFI_GUID*)model->header(index).left(16).constData())] = model->text(index); - + return db; } @@ -137,6 +137,6 @@ USTATUS guidDatabaseExportToFile(const UString & outPath, GuidDatabase & db) std::string name(it->second.toLocal8Bit()); outputFile << guid << ',' << name << '\n'; } - + return U_SUCCESS; } diff --git a/common/meparser.cpp b/common/meparser.cpp index e993058..f20a46a 100755 --- a/common/meparser.cpp +++ b/common/meparser.cpp @@ -1,16 +1,16 @@ /* meparser.cpp - -Copyright (c) 2019, 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2019, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include @@ -42,30 +42,30 @@ USTATUS MeParser::parseMeRegionBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Obtain ME region UByteArray meRegion = model->body(index); - + // Check region size if ((UINT32)meRegion.size() < ME_ROM_BYPASS_VECTOR_SIZE + sizeof(UINT32)) { msg(usprintf("%s: ME region too small to fit ROM bypass vector", __FUNCTION__), index); return U_INVALID_ME_PARTITION_TABLE; } - + // Check ME signature to determine it's version // ME v11 and older layout if (meRegion.left(sizeof(UINT32)) == FPT_HEADER_SIGNATURE || meRegion.mid(ME_ROM_BYPASS_VECTOR_SIZE, sizeof(UINT32)) == FPT_HEADER_SIGNATURE) { UModelIndex ptIndex; return parseFptRegion(meRegion, index, ptIndex); } - + // IFWI 1.6 // Check region size if ((UINT32)meRegion.size() < sizeof(IFWI_16_LAYOUT_HEADER)) { msg(usprintf("%s: ME region too small to fit IFWI 1.6 layout header", __FUNCTION__), index); return U_INVALID_ME_PARTITION_TABLE; } - + const IFWI_16_LAYOUT_HEADER* ifwi16Header = (const IFWI_16_LAYOUT_HEADER*)meRegion.constData(); // Check region size if ((UINT32)meRegion.size() < ifwi16Header->DataPartition.Offset + sizeof(UINT32)) { @@ -77,7 +77,7 @@ USTATUS MeParser::parseMeRegionBody(const UModelIndex & index) UModelIndex ptIndex; return parseIfwi16Region(meRegion, index, ptIndex); } - + // IFWI 1.7 if ((UINT32)meRegion.size() < sizeof(IFWI_17_LAYOUT_HEADER)) { msg(usprintf("%s: ME region too small to fit IFWI 1.7 layout header", __FUNCTION__), index); @@ -95,7 +95,7 @@ USTATUS MeParser::parseMeRegionBody(const UModelIndex & index) UModelIndex ptIndex; return parseIfwi17Region(meRegion, index, ptIndex); } - + // Something else entirely msg(usprintf("%s: unknown ME region format", __FUNCTION__), index); return U_INVALID_ME_PARTITION_TABLE; @@ -138,41 +138,41 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex & const FPT_HEADER_21* ptHeader21 = (const FPT_HEADER_21*)ptHeader; info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nROM bypass vector: %s\nNumber of entries: %u\nHeader version: %02Xh\nEntry version: %02Xh\n" - "Header length: %02Xh\nFlags: %Xh\nTicks to add: %04Xh\nTokens to add: %04Xh\nSPS Flags: %Xh\nFITC version: %u.%u.%u.%u\nCRC32 Checksum: %08Xh", - ptSize, ptSize, - header.size(), header.size(), - ptBodySize, ptBodySize, - (romBypassVectorSize ? "present" : "absent"), - ptHeader21->NumEntries, - ptHeader21->HeaderVersion, - ptHeader21->EntryVersion, - ptHeader21->HeaderLength, - ptHeader21->Flags, - ptHeader21->TicksToAdd, - ptHeader21->TokensToAdd, - ptHeader21->SPSFlags, - ptHeader21->FitcMajor, ptHeader21->FitcMinor, ptHeader21->FitcHotfix, ptHeader21->FitcBuild, - ptHeader21->HeaderCrc32); + "Header length: %02Xh\nFlags: %Xh\nTicks to add: %04Xh\nTokens to add: %04Xh\nSPS Flags: %Xh\nFITC version: %u.%u.%u.%u\nCRC32 Checksum: %08Xh", + ptSize, ptSize, + (UINT32)header.size(), (UINT32)header.size(), + ptBodySize, ptBodySize, + (romBypassVectorSize ? "present" : "absent"), + ptHeader21->NumEntries, + ptHeader21->HeaderVersion, + ptHeader21->EntryVersion, + ptHeader21->HeaderLength, + ptHeader21->Flags, + ptHeader21->TicksToAdd, + ptHeader21->TokensToAdd, + ptHeader21->SPSFlags, + ptHeader21->FitcMajor, ptHeader21->FitcMinor, ptHeader21->FitcHotfix, ptHeader21->FitcBuild, + ptHeader21->HeaderCrc32); // TODO: verify header crc32 } // Default handling for all other versions, may be too generic in some corner cases else { info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nROM bypass vector: %s\nNumber of entries: %u\nHeader version: %02Xh\nEntry version: %02Xh\n" - "Header length: %02Xh\nFlash cycle life: %04Xh\nFlash cycle limit: %04Xh\nUMA size: %Xh\nFlags: %Xh\nFITC version: %u.%u.%u.%u\nChecksum: %02Xh", - ptSize, ptSize, - header.size(), header.size(), - ptBodySize, ptBodySize, - (romBypassVectorSize ? "present" : "absent"), - ptHeader->NumEntries, - ptHeader->HeaderVersion, - ptHeader->EntryVersion, - ptHeader->HeaderLength, - ptHeader->FlashCycleLife, - ptHeader->FlashCycleLimit, - ptHeader->UmaSize, - ptHeader->Flags, - ptHeader->FitcMajor, ptHeader->FitcMinor, ptHeader->FitcHotfix, ptHeader->FitcBuild, - ptHeader->HeaderChecksum); + "Header length: %02Xh\nFlash cycle life: %04Xh\nFlash cycle limit: %04Xh\nUMA size: %Xh\nFlags: %Xh\nFITC version: %u.%u.%u.%u\nChecksum: %02Xh", + ptSize, ptSize, + (UINT32)header.size(), (UINT32)header.size(), + ptBodySize, ptBodySize, + (romBypassVectorSize ? "present" : "absent"), + ptHeader->NumEntries, + ptHeader->HeaderVersion, + ptHeader->EntryVersion, + ptHeader->HeaderLength, + ptHeader->FlashCycleLife, + ptHeader->FlashCycleLimit, + ptHeader->UmaSize, + ptHeader->Flags, + ptHeader->FitcMajor, ptHeader->FitcMinor, ptHeader->FitcHotfix, ptHeader->FitcBuild, + ptHeader->HeaderChecksum); // TODO: verify header checksum8 } @@ -213,7 +213,7 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex & partitions.push_back(partition); } } - + make_partition_table_consistent: // Sort partitions by offset std::sort(partitions.begin(), partitions.end()); @@ -251,7 +251,7 @@ make_partition_table_consistent: partitions[i].ptEntry.Size = (UINT32)region.size() - (UINT32)partitions[i].ptEntry.Offset; } } - + // Check for intersection with previous partition if (partitions[i].ptEntry.Offset < previousPartitionEnd) { // Check if current partition is located inside previous one @@ -295,9 +295,9 @@ make_partition_table_consistent: // Get info name = visibleAsciiOrHex((UINT8*) partitions[i].ptEntry.Name, 4); info = usprintf("Full size: %Xh (%u)\nPartition type: %02Xh\n", - partition.size(), partition.size(), - partitions[i].ptEntry.Type); - + (UINT32)partition.size(), (UINT32)partition.size(), + partitions[i].ptEntry.Type); + // Add tree item UINT8 type = Subtypes::CodeFptPartition + partitions[i].ptEntry.Type; partitionIndex = model->addItem(partitions[i].ptEntry.Offset, Types::FptPartition, type, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); @@ -310,7 +310,7 @@ make_partition_table_consistent: else if (partitions[i].type == Types::Padding) { // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size()); + info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size()); // Add tree item model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); @@ -343,7 +343,7 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex "Boot4 partition offset: %Xh\nBoot4 partition size: %Xh\n" "Boot5 partition offset: %Xh\nBoot5 partition size: %Xh\n" "Checksum: %llXh", - header.size(), header.size(), + (UINT32)header.size(), (UINT32)header.size(), ifwiHeader->DataPartition.Offset, ifwiHeader->DataPartition.Size, ifwiHeader->BootPartition[0].Offset, ifwiHeader->BootPartition[0].Size, ifwiHeader->BootPartition[1].Offset, ifwiHeader->BootPartition[1].Size, @@ -373,7 +373,7 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex partitions.push_back(partition); } } - + make_partition_table_consistent: // Sort partitions by offset std::sort(partitions.begin(), partitions.end()); @@ -457,8 +457,7 @@ make_partition_table_consistent: } // Get info - info = usprintf("Full size: %Xh (%u)\n", - partition.size(), partition.size()); + info = usprintf("Full size: %Xh (%u)\n", (UINT32)partition.size(), (UINT32)partition.size()); // Add tree item partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); @@ -477,13 +476,13 @@ make_partition_table_consistent: else if (partitions[i].type == Types::Padding) { // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size()); + info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size()); // Add tree item model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); } } - + return U_SUCCESS; } @@ -514,7 +513,7 @@ USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex "Boot4 partition offset: %Xh\nBoot4 partition size: %Xh\n" "Boot5 partition offset: %Xh\nBoot5 partition size: %Xh\n" "Temp page offset: %Xh\nTemp page size: %Xh\n", - header.size(), header.size(), + (UINT32)header.size(), (UINT32)header.size(), ifwiHeader->Flags, ifwiHeader->Reserved, ifwiHeader->Checksum, @@ -643,8 +642,7 @@ make_partition_table_consistent: } // Get info - info = usprintf("Full size: %Xh (%u)\n", - partition.size(), partition.size()); + info = usprintf("Full size: %Xh (%u)\n", (UINT32)partition.size(), (UINT32)partition.size()); // Add tree item partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); @@ -663,7 +661,7 @@ make_partition_table_consistent: else if (partitions[i].type == Types::Padding) { // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size()); + info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size()); // Add tree item model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent); diff --git a/common/nvram.cpp b/common/nvram.cpp index e43dac5..a914153 100644 --- a/common/nvram.cpp +++ b/common/nvram.cpp @@ -1,15 +1,15 @@ /* nvram.cpp -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 -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + 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 + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "nvram.h" @@ -17,7 +17,7 @@ UString nvarAttributesToUString(const UINT8 attributes) { if (attributes == 0x00 || attributes == 0xFF) return UString(); - + UString str; if (attributes & NVRAM_NVAR_ENTRY_RUNTIME) str += UString(", Runtime"); if (attributes & NVRAM_NVAR_ENTRY_ASCII_NAME) str += UString(", AsciiName"); @@ -39,7 +39,7 @@ UString nvarExtendedAttributesToUString(const UINT8 attributes) if (attributes & NVRAM_NVAR_ENTRY_EXT_AUTH_WRITE) str += UString(", AuthWrite"); if (attributes & NVRAM_NVAR_ENTRY_EXT_TIME_BASED) str += UString(", TimeBasedAuthWrite"); if (attributes & NVRAM_NVAR_ENTRY_EXT_UNKNOWN_MASK) str += UString(", Unknown"); - + str.remove(0, 2); // Remove first comma and space return str; } @@ -56,7 +56,7 @@ extern UString vssAttributesToUString(const UINT32 attributes) if (attributes & NVRAM_VSS_VARIABLE_APPEND_WRITE) str += UString(", AppendWrite"); if (attributes & NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM) str += UString(", AppleChecksum"); if (attributes & NVRAM_VSS_VARIABLE_UNKNOWN_MASK) str += UString(", Unknown"); - + str.remove(0, 2); // Remove first comma and space return str; } @@ -73,7 +73,7 @@ UString evsaAttributesToUString(const UINT32 attributes) if (attributes & NVRAM_EVSA_DATA_APPEND_WRITE) str += UString(", AppendWrite"); if (attributes & NVRAM_EVSA_DATA_EXTENDED_HEADER) str += UString(", ExtendedHeader"); if (attributes & NVRAM_EVSA_DATA_UNKNOWN_MASK) str += UString(", Unknown"); - + str.remove(0, 2); // Remove first comma and space return str; } @@ -81,13 +81,13 @@ UString evsaAttributesToUString(const UINT32 attributes) UString efiTimeToUString(const EFI_TIME & time) { return usprintf("%04u-%02u-%02uT%02u:%02u:%02u.%u", - time.Year, - time.Month, - time.Day, - time.Hour, - time.Minute, - time.Second, - time.Nanosecond); + time.Year, + time.Month, + time.Day, + time.Hour, + time.Minute, + time.Second, + time.Nanosecond); } UString flashMapGuidToUString(const EFI_GUID & guid) @@ -96,9 +96,9 @@ UString flashMapGuidToUString(const EFI_GUID & guid) if (baGuid == NVRAM_PHOENIX_FLASH_MAP_VOLUME_HEADER) return UString("Volume header"); if (baGuid == NVRAM_PHOENIX_FLASH_MAP_MICROCODES_GUID) return UString("Microcodes"); if (baGuid == NVRAM_PHOENIX_FLASH_MAP_CMDB_GUID) return UString("CMDB"); - if (baGuid == NVRAM_PHOENIX_FLASH_MAP_PUBKEY1_GUID + if (baGuid == NVRAM_PHOENIX_FLASH_MAP_PUBKEY1_GUID || baGuid == NVRAM_PHOENIX_FLASH_MAP_PUBKEY2_GUID) return UString("SLIC pubkey"); - if (baGuid == NVRAM_PHOENIX_FLASH_MAP_MARKER1_GUID + if (baGuid == NVRAM_PHOENIX_FLASH_MAP_MARKER1_GUID || baGuid == NVRAM_PHOENIX_FLASH_MAP_MARKER2_GUID) return UString("SLIC marker"); if (baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA1_GUID || baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA2_GUID diff --git a/common/nvramparser.cpp b/common/nvramparser.cpp index 2da6530..2ee4f87 100755 --- a/common/nvramparser.cpp +++ b/common/nvramparser.cpp @@ -1,16 +1,16 @@ /* nvramparser.cpp - -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 -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + 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 + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ //TODO: relax fixed restrictions once NVRAM builder is ready @@ -30,7 +30,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Obtain required information from parent file UINT8 emptyByte = 0xFF; UModelIndex parentFileIndex = model->findParentOfType(index, Types::File); @@ -39,13 +39,13 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) const FILE_PARSING_DATA* pdata = (const FILE_PARSING_DATA*)data.constData(); emptyByte = readUnaligned(pdata).emptyByte; } - + // Get local offset UINT32 localOffset = (UINT32)model->header(index).size(); - + // Get item data const UByteArray data = model->body(index); - + // Parse all entries UINT32 offset = 0; UINT32 guidsInStore = 0; @@ -53,7 +53,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) bool msgUnknownExtDataFormat = false; bool msgExtHeaderTooLong = false; bool msgExtDataTooShort = false; - + bool isInvalid = false; bool isInvalidLink = false; bool hasExtendedHeader = false; @@ -61,7 +61,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) bool hasTimestamp = false; bool hasHash = false; bool hasGuidIndex = false; - + UINT32 guidIndex = 0; UINT8 storedChecksum = 0; UINT8 calculatedChecksum = 0; @@ -69,7 +69,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) UINT8 extendedAttributes = 0; UINT64 timestamp = 0; UByteArray hash; - + UINT8 subtype = Subtypes::FullNvarEntry; UString name; UString guid; @@ -77,23 +77,23 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) UByteArray header; UByteArray body; UByteArray tail; - + UINT32 guidAreaSize = guidsInStore * sizeof(EFI_GUID); UINT32 unparsedSize = (UINT32)data.size() - offset - guidAreaSize; - + // Get entry header const NVAR_ENTRY_HEADER* entryHeader = (const NVAR_ENTRY_HEADER*)(data.constData() + offset); - + // Check header size and signature if (unparsedSize < sizeof(NVAR_ENTRY_HEADER) || entryHeader->Signature != NVRAM_NVAR_ENTRY_SIGNATURE || unparsedSize < entryHeader->Size) { // Check if the data left is a free space or a padding UByteArray padding = data.mid(offset, unparsedSize); - + // Get info - UString info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + if ((UINT32)padding.count(emptyByte) == unparsedSize) { // Free space // Add tree item model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); @@ -104,53 +104,53 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) msg(usprintf("%s: file can't be parsed as NVAR variables store", __FUNCTION__), index); return U_SUCCESS; } - + // Add tree item model->addItem(localOffset + offset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + // Add GUID store area UByteArray guidArea = data.right(guidAreaSize); // Get info name = UString("GUID store"); info = usprintf("Full size: %Xh (%u)\nGUIDs in store: %u", - guidArea.size(), guidArea.size(), - guidsInStore); + (UINT32)guidArea.size(), (UINT32)guidArea.size(), + guidsInStore); // Add tree item model->addItem((UINT32)(localOffset + offset + padding.size()), Types::Padding, getPaddingType(guidArea), name, UString(), info, UByteArray(), guidArea, UByteArray(), Fixed, index); - + return U_SUCCESS; } - + // Contruct generic header and body header = data.mid(offset, sizeof(NVAR_ENTRY_HEADER)); body = data.mid(offset + sizeof(NVAR_ENTRY_HEADER), entryHeader->Size - sizeof(NVAR_ENTRY_HEADER)); - + UINT32 lastVariableFlag = emptyByte ? 0xFFFFFF : 0; - + // Set default next to predefined last value NVAR_ENTRY_PARSING_DATA pdata = {}; pdata.emptyByte = emptyByte; pdata.next = lastVariableFlag; - + // Entry is marked as invalid if ((entryHeader->Attributes & NVRAM_NVAR_ENTRY_VALID) == 0) { // Valid attribute is not set isInvalid = true; // Do not parse further goto parsing_done; } - + // Add next node information to parsing data if (entryHeader->Next != lastVariableFlag) { subtype = Subtypes::LinkNvarEntry; pdata.next = entryHeader->Next; } - + // Entry with extended header if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_EXT_HEADER) { hasExtendedHeader = true; msgUnknownExtDataFormat = true; - + extendedHeaderSize = readUnaligned((UINT16*)(body.constData() + body.size() - sizeof(UINT16))); if (extendedHeaderSize > (UINT32)body.size()) { msgExtHeaderTooLong = true; @@ -158,14 +158,14 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Do not parse further goto parsing_done; } - + extendedAttributes = *(UINT8*)(body.constData() + body.size() - extendedHeaderSize); - + // Variable with checksum if (extendedAttributes & NVRAM_NVAR_ENTRY_EXT_CHECKSUM) { // Get stored checksum storedChecksum = *(UINT8*)(body.constData() + body.size() - sizeof(UINT16) - sizeof(UINT8)); - + // Recalculate checksum for the variable calculatedChecksum = 0; // Include entry data @@ -180,14 +180,14 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) } // Include entry attributes calculatedChecksum += entryHeader->Attributes; - + hasChecksum = true; msgUnknownExtDataFormat = false; } - + tail = body.mid(body.size() - extendedHeaderSize); body = body.left(body.size() - extendedHeaderSize); - + // Entry with authenticated write (for SecureBoot) if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_AUTH_WRITE) { if ((entryHeader->Attributes & NVRAM_NVAR_ENTRY_DATA_ONLY)) {// Data only auth. variables has no hash @@ -197,7 +197,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Do not parse further goto parsing_done; } - + timestamp = readUnaligned(tail.constData() + sizeof(UINT8)); hasTimestamp = true; msgUnknownExtDataFormat = false; @@ -209,7 +209,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Do not parse further goto parsing_done; } - + timestamp = readUnaligned((UINT64*)(tail.constData() + sizeof(UINT8))); hash = tail.mid(sizeof(UINT64) + sizeof(UINT8), SHA256_HASH_SIZE); hasTimestamp = true; @@ -218,7 +218,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) } } } - + // Entry is data-only (nameless and GUIDless entry or link) if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_DATA_ONLY) { // Data-only attribute is set isInvalidLink = true; @@ -227,7 +227,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // WARNING: O(n^2), may be very slow for (int i = model->rowCount(index) - 1; i >= 0; i--) { nvarIndex = index.model()->index(i, 0, index); - + if (model->hasEmptyParsingData(nvarIndex) == false) { UByteArray nvarData = model->parsingData(nvarIndex); const NVAR_ENTRY_PARSING_DATA nvarPdata = readUnaligned((const NVAR_ENTRY_PARSING_DATA*)nvarData.constData()); @@ -242,15 +242,15 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) // Use the name and text of the previous link name = model->name(nvarIndex); text = model->text(nvarIndex); - + if (entryHeader->Next == lastVariableFlag) subtype = Subtypes::DataNvarEntry; } - + // Do not parse further goto parsing_done; } - + // Get entry name { UINT32 nameOffset = (entryHeader->Attributes & NVRAM_NVAR_ENTRY_GUID) ? sizeof(EFI_GUID) : sizeof(UINT8); // GUID can be stored with the variable or in a separate store, so there will only be an index of it @@ -266,10 +266,10 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) #else text = UString::fromUtf16((CHAR16*)namePtr); #endif - + nameSize = (UINT32)((text.length() + 1) * 2); } - + // Get entry GUID if (entryHeader->Attributes & NVRAM_NVAR_ENTRY_GUID) { // GUID is strored in the variable itself name = guidToUString(readUnaligned((EFI_GUID*)(entryHeader + 1))); @@ -280,21 +280,21 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) guidIndex = *(UINT8*)(entryHeader + 1); if (guidsInStore < guidIndex + 1) guidsInStore = guidIndex + 1; - + // The list begins at the end of the store and goes backwards const EFI_GUID* guidPtr = (const EFI_GUID*)(data.constData() + data.size()) - 1 - guidIndex; name = guidToUString(readUnaligned(guidPtr)); guid = guidToUString(readUnaligned(guidPtr), false); hasGuidIndex = true; } - + // Include name and GUID into the header and remove them from body header = data.mid(offset, sizeof(NVAR_ENTRY_HEADER) + nameOffset + nameSize); body = body.mid(nameOffset + nameSize); } parsing_done: UString info; - + // Rename invalid entries according to their types pdata.isValid = TRUE; if (isInvalid) { @@ -309,69 +309,69 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index) } else // Add GUID info for valid entries info += UString("Variable GUID: ") + guid + UString("\n"); - + // Add GUID index information if (hasGuidIndex) info += usprintf("GUID index: %u\n", guidIndex); - + // Add header, body and extended data info info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - entryHeader->Size, entryHeader->Size, - header.size(), header.size(), - body.size(), body.size()); - + entryHeader->Size, entryHeader->Size, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size()); + // Add attributes info info += usprintf("\nAttributes: %02Xh", entryHeader->Attributes); // Translate attributes to text if (entryHeader->Attributes && entryHeader->Attributes != 0xFF) info += UString(" (") + nvarAttributesToUString(entryHeader->Attributes) + UString(")"); - + // Add next node info if (!isInvalid && entryHeader->Next != lastVariableFlag) info += usprintf("\nNext node at offset: %Xh", localOffset + offset + entryHeader->Next); - + // Add extended header info if (hasExtendedHeader) { info += usprintf("\nExtended header size: %Xh (%u)\nExtended attributes: %Xh (", - extendedHeaderSize, extendedHeaderSize, - extendedAttributes) + nvarExtendedAttributesToUString(extendedAttributes) + UString(")"); - + extendedHeaderSize, extendedHeaderSize, + extendedAttributes) + nvarExtendedAttributesToUString(extendedAttributes) + UString(")"); + // Add checksum if (hasChecksum) info += usprintf("\nChecksum: %02Xh", storedChecksum) + (calculatedChecksum ? usprintf(", invalid, should be %02Xh", 0x100 - calculatedChecksum) : UString(", valid")); - + // Add timestamp if (hasTimestamp) info += usprintf("\nTimestamp: %" PRIX64 "h", timestamp); - + // Add hash if (hasHash) info += UString("\nHash: ") + UString(hash.toHex().constData()); } - + // Add tree item UModelIndex varIndex = model->addItem(localOffset + offset, Types::NvarEntry, subtype, name, text, info, header, body, tail, Fixed, index); - + // Set parsing data for created entry model->setParsingData(varIndex, UByteArray((const char*)&pdata, sizeof(pdata))); - + // Show messages if (msgUnknownExtDataFormat) msg(usprintf("%s: unknown extended data format", __FUNCTION__), varIndex); if (msgExtHeaderTooLong) msg(usprintf("%s: extended header size (%Xh) is greater than body size (%Xh)", __FUNCTION__, - extendedHeaderSize, body.size()), varIndex); + extendedHeaderSize, (UINT32)body.size()), varIndex); if (msgExtDataTooShort) msg(usprintf("%s: extended header size (%Xh) is too small for timestamp and hash", __FUNCTION__, - tail.size()), varIndex); - + (UINT32)tail.size()), varIndex); + // Try parsing the entry data as NVAR storage if it begins with NVAR signature if ((subtype == Subtypes::DataNvarEntry || subtype == Subtypes::FullNvarEntry) && body.size() >= 4 && readUnaligned((const UINT32*)body.constData()) == NVRAM_NVAR_ENTRY_SIGNATURE) parseNvarStore(varIndex); - + // Move to next exntry offset += entryHeader->Size; } - + return U_SUCCESS; } @@ -380,7 +380,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Obtain required fields from parsing data UINT8 emptyByte = 0xFF; if (model->hasEmptyParsingData(index) == false) { @@ -388,20 +388,20 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); emptyByte = pdata->emptyByte; } - + // Get local offset UINT32 localOffset = (UINT32)model->header(index).size(); - + // Get item data UByteArray data = model->body(index); - + // Search for first store USTATUS result; UINT32 prevStoreOffset; result = findNextStore(index, data, localOffset, 0, prevStoreOffset); if (result) return result; - + // First store is not at the beginning of volume body UString name; UString info; @@ -409,31 +409,31 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) // Get info UByteArray padding = data.left(prevStoreOffset); name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item model->addItem(localOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + // Search for and parse all stores UINT32 storeOffset = prevStoreOffset; UINT32 prevStoreSize = 0; - + while (!result) { // Padding between stores if (storeOffset > prevStoreOffset + prevStoreSize) { UINT32 paddingOffset = prevStoreOffset + prevStoreSize; UINT32 paddingSize = storeOffset - paddingOffset; UByteArray padding = data.mid(paddingOffset, paddingSize); - + // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item model->addItem(localOffset + paddingOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + // Get store size UINT32 storeSize = 0; result = getStoreSize(data, storeOffset, storeSize); @@ -441,46 +441,46 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) msg(usprintf("%s: getStoreSize failed with error ", __FUNCTION__) + errorCodeToUString(result), index); return result; } - + // Check that current store is fully present in input if (storeSize > (UINT32)data.size() || storeOffset + storeSize > (UINT32)data.size()) { // Mark the rest as padding and finish parsing UByteArray padding = data.mid(storeOffset); - + // Get info name = UString("Padding"); - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + // Add tree item UModelIndex paddingIndex = model->addItem(localOffset + storeOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); msg(usprintf("%s: one of stores inside overlaps the end of data", __FUNCTION__), paddingIndex); - + // Update variables prevStoreOffset = storeOffset; prevStoreSize = (UINT32)padding.size(); break; } - + // Parse current store header UModelIndex storeIndex; UByteArray store = data.mid(storeOffset, storeSize); result = parseStoreHeader(store, localOffset + storeOffset, index, storeIndex); if (result) msg(usprintf("%s: store header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index); - + // Go to next store prevStoreOffset = storeOffset; prevStoreSize = storeSize; result = findNextStore(index, data, localOffset, storeOffset + prevStoreSize, storeOffset); } - + // Padding/free space at the end storeOffset = prevStoreOffset + prevStoreSize; if ((UINT32)data.size() > storeOffset) { UByteArray padding = data.mid(storeOffset); // Add info - info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + if (padding.count(emptyByte) == padding.size()) { // Free space // Add tree item model->addItem(localOffset + storeOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); @@ -491,51 +491,51 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index) msg(usprintf("%s: can't be parsed as NVRAM volume", __FUNCTION__), index); return U_SUCCESS; } - + // Add tree item model->addItem(localOffset + storeOffset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } } - + // Parse bodies for (int i = 0; i < model->rowCount(index); i++) { UModelIndex current = index.model()->index(i, 0, index); - + switch (model->type(current)) { - case Types::FdcStore: - parseFdcStoreBody(current); - break; - case Types::VssStore: - parseVssStoreBody(current, 0); - break; - case Types::Vss2Store: - parseVssStoreBody(current, 4); - break; - case Types::FsysStore: - parseFsysStoreBody(current); - break; - case Types::EvsaStore: - parseEvsaStoreBody(current); - break; - case Types::FlashMapStore: - parseFlashMapBody(current); - break; - default: - // Ignore unknown! - break; + case Types::FdcStore: + parseFdcStoreBody(current); + break; + case Types::VssStore: + parseVssStoreBody(current, 0); + break; + case Types::Vss2Store: + parseVssStoreBody(current, 4); + break; + case Types::FsysStore: + parseFsysStoreBody(current); + break; + case Types::EvsaStore: + parseEvsaStoreBody(current); + break; + case Types::FlashMapStore: + parseFlashMapBody(current); + break; + default: + // Ignore unknown! + break; } } - + return U_SUCCESS; } USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & volume, const UINT32 localOffset, const UINT32 storeOffset, UINT32 & nextStoreOffset) { UINT32 dataSize = (UINT32)volume.size(); - + if (dataSize < sizeof(UINT32)) return U_STORES_NOT_FOUND; - + // TODO: add checks for restSize UINT32 offset = storeOffset; for (; offset < dataSize - sizeof(UINT32); offset++) { @@ -557,7 +557,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); if (guid != NVRAM_VSS2_AUTH_VAR_KEY_DATABASE_GUID && guid != NVRAM_VSS2_STORE_GUID) // Check the whole signature continue; - + const VSS2_VARIABLE_STORE_HEADER* vssHeader = (const VSS2_VARIABLE_STORE_HEADER*)currentPos; if (vssHeader->Format != NVRAM_VSS_VARIABLE_STORE_FORMATTED) { msg(usprintf("%s: VSS2 store candidate at offset %Xh skipped, has invalid format %02Xh", __FUNCTION__, localOffset + offset, vssHeader->Format), index); @@ -591,7 +591,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & else if (*currentPos == NVRAM_EVSA_STORE_SIGNATURE) { //EVSA signature found if (offset < sizeof(UINT32)) continue; - + const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)(currentPos - 1); if (evsaHeader->Header.Type != NVRAM_EVSA_ENTRY_TYPE_STORE) { msg(usprintf("%s: EVSA store candidate at offset %Xh skipped, has invalid type %02Xh", __FUNCTION__, localOffset + offset - 4, evsaHeader->Header.Type), index); @@ -609,7 +609,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & UByteArray guid = UByteArray(volume.constData() + offset, sizeof(EFI_GUID)); if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID && guid != VSS2_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature continue; - + // Detect header variant based on WriteQueueSize const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftwHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)currentPos; if (ftwHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize @@ -627,7 +627,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & } else // Unknown header continue; - + // All checks passed, store found break; } @@ -635,17 +635,17 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & UByteArray signature = UByteArray(volume.constData() + offset, NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_LENGTH); if (signature != NVRAM_PHOENIX_FLASH_MAP_SIGNATURE) // Check the whole signature continue; - + // All checks passed, store found break; } else if (*currentPos == NVRAM_PHOENIX_CMDB_HEADER_SIGNATURE) { // Phoenix SCT CMDB store const PHOENIX_CMDB_HEADER* cmdbHeader = (const PHOENIX_CMDB_HEADER*)currentPos; - + // Check size if (cmdbHeader->HeaderSize != sizeof(PHOENIX_CMDB_HEADER)) continue; - + // All checks passed, store found break; } @@ -656,19 +656,19 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & if (FALSE == ffsParser->microcodeHeaderValid(ucodeHeader)) { continue; } - + // All checks passed, store found break; } else if (*currentPos == OEM_ACTIVATION_PUBKEY_MAGIC) { // SLIC pubkey if (offset < 4 * sizeof(UINT32)) continue; - + const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)(currentPos - 4); // Check type if (pubkeyHeader->Type != OEM_ACTIVATION_PUBKEY_TYPE) continue; - + // All checks passed, store found offset -= 4 * sizeof(UINT32); break; @@ -678,7 +678,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & || offset >= dataSize - sizeof(UINT64) || *(const UINT64*)currentPos != OEM_ACTIVATION_MARKER_WINDOWS_FLAG) // Check full windows flag and structure size continue; - + const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)(volume.constData() + offset - 26); // Check reserved bytes bool reservedBytesValid = true; @@ -689,7 +689,7 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & } if (!reservedBytesValid) continue; - + // All checks passed, store found offset -= 26; break; @@ -698,9 +698,9 @@ USTATUS NvramParser::findNextStore(const UModelIndex & index, const UByteArray & // No more stores found if (offset >= dataSize - sizeof(UINT32)) return U_STORES_NOT_FOUND; - + nextStoreOffset = offset; - + return U_SUCCESS; } @@ -764,34 +764,34 @@ USTATUS NvramParser::getStoreSize(const UByteArray & data, const UINT32 storeOff USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check store size if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) { msg(usprintf("%s: volume body is too small even for VSS store header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get VSS store header const VSS_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS_VARIABLE_STORE_HEADER*)store.constData(); - + // Check for size override UINT32 storeSize = vssStoreHeader->Size; if (sizeOverride) { storeSize = dataSize; } - + // Check store size if (dataSize < storeSize) { msg(usprintf("%s: VSS store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - storeSize, storeSize, - dataSize, dataSize), parent); + storeSize, storeSize, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(sizeof(VSS_VARIABLE_STORE_HEADER)); UByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS_VARIABLE_STORE_HEADER)); - + // Add info UString name; if (vssStoreHeader->Signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) { @@ -805,78 +805,78 @@ USTATUS NvramParser::parseVssStoreHeader(const UByteArray & store, const UINT32 } UString info = usprintf("Signature: %Xh\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", - vssStoreHeader->Signature, - storeSize, storeSize, - header.size(), header.size(), - body.size(), body.size(), - vssStoreHeader->Format, - vssStoreHeader->State, - vssStoreHeader->Unknown); - + vssStoreHeader->Signature, + storeSize, storeSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + vssStoreHeader->Format, + vssStoreHeader->State, + vssStoreHeader->Unknown); + // Add tree item index = model->addItem(localOffset, Types::VssStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseVss2StoreHeader(const UByteArray & store, const UINT32 localOffset, const bool sizeOverride, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check store size if (dataSize < sizeof(VSS2_VARIABLE_STORE_HEADER)) { msg(usprintf("%s: volume body is too small even for VSS2 store header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get VSS2 store header const VSS2_VARIABLE_STORE_HEADER* vssStoreHeader = (const VSS2_VARIABLE_STORE_HEADER*)store.constData(); - + // Check for size override UINT32 storeSize = vssStoreHeader->Size; if (sizeOverride) { storeSize = dataSize; } - + // Check store size if (dataSize < storeSize) { msg(usprintf("%s: VSS2 store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - storeSize, storeSize, - dataSize, dataSize), parent); + storeSize, storeSize, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(sizeof(VSS2_VARIABLE_STORE_HEADER)); UByteArray body = store.mid(sizeof(VSS2_VARIABLE_STORE_HEADER), storeSize - sizeof(VSS2_VARIABLE_STORE_HEADER)); - + // Add info UString name = UString("VSS2 store"); UString info = UString("Signature: ") + guidToUString(vssStoreHeader->Signature, false) + - usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", - storeSize, storeSize, - header.size(), header.size(), - body.size(), body.size(), - vssStoreHeader->Format, - vssStoreHeader->State, - vssStoreHeader->Unknown); - + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nFormat: %02Xh\nState: %02Xh\nUnknown: %04Xh", + storeSize, storeSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + vssStoreHeader->Format, + vssStoreHeader->State, + vssStoreHeader->Unknown); + // Add tree item index = model->addItem(localOffset, Types::Vss2Store, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check store size if (dataSize < sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64)) { msg(usprintf("%s: volume body is too small even for FTW store header", __FUNCTION__), parent); return U_SUCCESS; } - + // Obtain required information from parent volume UINT8 emptyByte = 0xFF; UModelIndex parentVolumeIndex = model->findParentOfType(parent, Types::Volume); @@ -885,11 +885,11 @@ USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32 const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); emptyByte = pdata->emptyByte; } - + // Get FTW block headers const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftw32BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)store.constData(); const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)store.constData(); - + // Check store size UINT32 ftwBlockSize; bool has32bitHeader; @@ -903,330 +903,330 @@ USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32 } if (dataSize < ftwBlockSize) { msg(usprintf("%s: FTW store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - ftwBlockSize, ftwBlockSize, - dataSize, dataSize), parent); + ftwBlockSize, ftwBlockSize, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UINT32 headerSize = has32bitHeader ? sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) : sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64); UByteArray header = store.left(headerSize); UByteArray body = store.mid(headerSize, ftwBlockSize - headerSize); - + // Check block header checksum UByteArray crcHeader = header; EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* crcFtwBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)header.data(); crcFtwBlockHeader->Crc = emptyByte ? 0xFFFFFFFF : 0; crcFtwBlockHeader->State = emptyByte ? 0xFF : 0; UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)crcFtwBlockHeader, headerSize); - + // Add info UString name("FTW store"); UString info = UString("Signature: ") + guidToUString(ftw32BlockHeader->Signature, false) + - usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nHeader CRC32: %08Xh", - ftwBlockSize, ftwBlockSize, - headerSize, headerSize, - body.size(), body.size(), - ftw32BlockHeader->State, - ftw32BlockHeader->Crc) + - (ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); - + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nHeader CRC32: %08Xh", + ftwBlockSize, ftwBlockSize, + headerSize, headerSize, + (UINT32)body.size(), (UINT32)body.size(), + ftw32BlockHeader->State, + ftw32BlockHeader->Crc) + + (ftw32BlockHeader->Crc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); + // Add tree item index = model->addItem(localOffset, Types::FtwStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseFdcStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check store size if (dataSize < sizeof(FDC_VOLUME_HEADER)) { msg(usprintf("%s: volume body is too small even for FDC store header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get Fdc store header const FDC_VOLUME_HEADER* fdcStoreHeader = (const FDC_VOLUME_HEADER*)store.constData(); - + // Check store size if (dataSize < fdcStoreHeader->Size) { msg(usprintf("%s: FDC store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - fdcStoreHeader->Size, fdcStoreHeader->Size, - dataSize, dataSize), parent); + fdcStoreHeader->Size, fdcStoreHeader->Size, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(sizeof(FDC_VOLUME_HEADER)); UByteArray body = store.mid(sizeof(FDC_VOLUME_HEADER), fdcStoreHeader->Size - sizeof(FDC_VOLUME_HEADER)); - + // Add info UString name("FDC store"); UString info = usprintf("Signature: _FDC\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - fdcStoreHeader->Size, fdcStoreHeader->Size, - header.size(), header.size(), - body.size(), body.size()); - + fdcStoreHeader->Size, fdcStoreHeader->Size, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size()); + // Add tree item index = model->addItem(localOffset, Types::FdcStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseFsysStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check store size if (dataSize < sizeof(APPLE_FSYS_STORE_HEADER)) { msg(usprintf("%s: volume body is too small even for Fsys store header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get Fsys store header const APPLE_FSYS_STORE_HEADER* fsysStoreHeader = (const APPLE_FSYS_STORE_HEADER*)store.constData(); - + // Check store size if (dataSize < fsysStoreHeader->Size) { msg(usprintf("%s: Fsys store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - fsysStoreHeader->Size, fsysStoreHeader->Size, - dataSize, dataSize), parent); + fsysStoreHeader->Size, fsysStoreHeader->Size, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(sizeof(APPLE_FSYS_STORE_HEADER)); UByteArray body = store.mid(sizeof(APPLE_FSYS_STORE_HEADER), fsysStoreHeader->Size - sizeof(APPLE_FSYS_STORE_HEADER) - sizeof(UINT32)); - + // Check store checksum UINT32 storedCrc = *(UINT32*)store.right(sizeof(UINT32)).constData(); UINT32 calculatedCrc = (UINT32)crc32(0, (const UINT8*)store.constData(), (UINT32)store.size() - sizeof(UINT32)); - + // Add info bool isGaidStore = (fsysStoreHeader->Signature == NVRAM_APPLE_GAID_STORE_SIGNATURE); UString name = isGaidStore ? UString("Gaid store") : UString("Fsys store"); UString info = usprintf("Signature: %s\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nUnknown0: %02Xh\nUnknown1: %08Xh\nCRC32: %08Xh", - isGaidStore ? "Gaid" : "Fsys", - fsysStoreHeader->Size, fsysStoreHeader->Size, - header.size(), header.size(), - body.size(), body.size(), - fsysStoreHeader->Unknown0, - fsysStoreHeader->Unknown1, - storedCrc) - + (storedCrc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); - + isGaidStore ? "Gaid" : "Fsys", + fsysStoreHeader->Size, fsysStoreHeader->Size, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + fsysStoreHeader->Unknown0, + fsysStoreHeader->Unknown1, + storedCrc) + + (storedCrc != calculatedCrc ? usprintf(", invalid, should be %08Xh", calculatedCrc) : UString(", valid")); + // Add tree item index = model->addItem(localOffset, Types::FsysStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseEvsaStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check dataSize if (dataSize < sizeof(EVSA_STORE_ENTRY)) { msg(usprintf("%s: volume body is too small even for EVSA store header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get EVSA store header const EVSA_STORE_ENTRY* evsaStoreHeader = (const EVSA_STORE_ENTRY*)store.constData(); - + // Check store size if (dataSize < evsaStoreHeader->StoreSize) { msg(usprintf("%s: EVSA store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize, - dataSize, dataSize), parent); + evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(evsaStoreHeader->Header.Size); UByteArray body = store.mid(evsaStoreHeader->Header.Size, evsaStoreHeader->StoreSize - evsaStoreHeader->Header.Size); - + // Recalculate checksum UINT8 calculated = calculateChecksum8(((const UINT8*)evsaStoreHeader) + 2, evsaStoreHeader->Header.Size - 2); - + // Add info UString name("EVSA store"); UString info = usprintf("Signature: EVSA\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nAttributes: %08Xh\nChecksum: %02Xh", - evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize, - header.size(), header.size(), - body.size(), body.size(), - evsaStoreHeader->Header.Type, - evsaStoreHeader->Attributes, - evsaStoreHeader->Header.Checksum) + - (evsaStoreHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")); - + evsaStoreHeader->StoreSize, evsaStoreHeader->StoreSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + evsaStoreHeader->Header.Type, + evsaStoreHeader->Attributes, + evsaStoreHeader->Header.Checksum) + + (evsaStoreHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")); + // Add tree item index = model->addItem(localOffset, Types::EvsaStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseFlashMapStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check data size if (dataSize < sizeof(PHOENIX_FLASH_MAP_HEADER)) { msg(usprintf("%s: volume body is too small even for FlashMap block header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get FlashMap block header const PHOENIX_FLASH_MAP_HEADER* flashMapHeader = (const PHOENIX_FLASH_MAP_HEADER*)store.constData(); - + // Check store size UINT32 flashMapSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + flashMapHeader->NumEntries * sizeof(PHOENIX_FLASH_MAP_ENTRY); if (dataSize < flashMapSize) { msg(usprintf("%s: FlashMap block size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - flashMapSize, flashMapSize, - dataSize, dataSize), parent); + flashMapSize, flashMapSize, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(sizeof(PHOENIX_FLASH_MAP_HEADER)); UByteArray body = store.mid(sizeof(PHOENIX_FLASH_MAP_HEADER), flashMapSize - sizeof(PHOENIX_FLASH_MAP_HEADER)); - + // Add info UString name("Phoenix SCT flash map"); UString info = usprintf("Signature: _FLASH_MAP\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u", - flashMapSize, flashMapSize, - header.size(), header.size(), - body.size(), body.size(), - flashMapHeader->NumEntries); - + flashMapSize, flashMapSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + flashMapHeader->NumEntries); + // Add tree item index = model->addItem(localOffset, Types::FlashMapStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseCmdbStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check store size if (dataSize < sizeof(PHOENIX_CMDB_HEADER)) { msg(usprintf("%s: volume body is too small even for CMDB store header", __FUNCTION__), parent); return U_SUCCESS; } - + UINT32 cmdbSize = NVRAM_PHOENIX_CMDB_SIZE; if (dataSize < cmdbSize) { msg(usprintf("%s: CMDB store size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - cmdbSize, cmdbSize, - dataSize, dataSize), parent); + cmdbSize, cmdbSize, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Get store header const PHOENIX_CMDB_HEADER* cmdbHeader = (const PHOENIX_CMDB_HEADER*)store.constData(); - + // Construct header and body UByteArray header = store.left(cmdbHeader->TotalSize); UByteArray body = store.mid(cmdbHeader->TotalSize, cmdbSize - cmdbHeader->TotalSize); - + // Add info UString name("CMDB store"); UString info = usprintf("Signature: CMDB\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - cmdbSize, cmdbSize, - header.size(), header.size(), - body.size(), body.size()); - + cmdbSize, cmdbSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size()); + // Add tree item index = model->addItem(localOffset, Types::CmdbStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseSlicPubkeyHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check data size if (dataSize < sizeof(OEM_ACTIVATION_PUBKEY)) { msg(usprintf("%s: volume body is too small even for SLIC pubkey header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get SLIC pubkey header const OEM_ACTIVATION_PUBKEY* pubkeyHeader = (const OEM_ACTIVATION_PUBKEY*)store.constData(); - + // Check store size if (dataSize < pubkeyHeader->Size) { msg(usprintf("%s: SLIC pubkey size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - pubkeyHeader->Size, pubkeyHeader->Size, - dataSize, dataSize), parent); + pubkeyHeader->Size, pubkeyHeader->Size, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(sizeof(OEM_ACTIVATION_PUBKEY)); - + // Add info UString name("SLIC pubkey"); UString info = usprintf("Type: 0h\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\n" - "Key type: %02Xh\nVersion: %02Xh\nAlgorithm: %08Xh\nMagic: RSA1\nBit length: %08Xh\nExponent: %08Xh", - pubkeyHeader->Size, pubkeyHeader->Size, - header.size(), header.size(), - pubkeyHeader->KeyType, - pubkeyHeader->Version, - pubkeyHeader->Algorithm, - pubkeyHeader->BitLength, - pubkeyHeader->Exponent); - + "Key type: %02Xh\nVersion: %02Xh\nAlgorithm: %08Xh\nMagic: RSA1\nBit length: %08Xh\nExponent: %08Xh", + pubkeyHeader->Size, pubkeyHeader->Size, + (UINT32)header.size(), (UINT32)header.size(), + pubkeyHeader->KeyType, + pubkeyHeader->Version, + pubkeyHeader->Algorithm, + pubkeyHeader->BitLength, + pubkeyHeader->Exponent); + // Add tree item index = model->addItem(localOffset, Types::SlicData, Subtypes::PubkeySlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent); - + return U_SUCCESS; } USTATUS NvramParser::parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index) { const UINT32 dataSize = (UINT32)store.size(); - + // Check data size if (dataSize < sizeof(OEM_ACTIVATION_MARKER)) { msg(usprintf("%s: volume body is too small even for SLIC marker header", __FUNCTION__), parent); return U_SUCCESS; } - + // Get SLIC marker header const OEM_ACTIVATION_MARKER* markerHeader = (const OEM_ACTIVATION_MARKER*)store.constData(); - + // Check store size if (dataSize < markerHeader->Size) { msg(usprintf("%s: SLIC marker size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__, - markerHeader->Size, markerHeader->Size, - dataSize, dataSize), parent); + markerHeader->Size, markerHeader->Size, + dataSize, dataSize), parent); return U_SUCCESS; } - + // Construct header and body UByteArray header = store.left(sizeof(OEM_ACTIVATION_MARKER)); - + // Add info UString name("SLIC marker"); UString info = usprintf("Type: 1h\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: 0h (0)\n" - "Version: %08Xh\nOEM ID: %s\nOEM table ID: %s\nWindows flag: WINDOWS\nSLIC version: %08Xh", - markerHeader->Size, markerHeader->Size, - header.size(), header.size(), - markerHeader->Version, - (const char*)UString((const char*)&(markerHeader->OemId)).left(6).toLocal8Bit(), - (const char*)UString((const char*)&(markerHeader->OemTableId)).left(8).toLocal8Bit(), - markerHeader->SlicVersion); - - + "Version: %08Xh\nOEM ID: %s\nOEM table ID: %s\nWindows flag: WINDOWS\nSLIC version: %08Xh", + markerHeader->Size, markerHeader->Size, + (UINT32)header.size(), (UINT32)header.size(), + markerHeader->Version, + (const char*)UString((const char*)&(markerHeader->OemId)).left(6).toLocal8Bit(), + (const char*)UString((const char*)&(markerHeader->OemTableId)).left(8).toLocal8Bit(), + markerHeader->SlicVersion); + + // Add tree item index = model->addItem(localOffset, Types::SlicData, Subtypes::MarkerSlicData, name, UString(), info, header, UByteArray(), UByteArray(), Fixed, parent); - + return U_SUCCESS; } @@ -1239,7 +1239,7 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc msg(usprintf("%s: volume body is too small even for a store signature", __FUNCTION__), parent); return U_SUCCESS; } - + // Check signature and run parser function needed // VSS/SVS/NSS store if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE || *signature == NVRAM_APPLE_NSS_STORE_SIGNATURE) @@ -1275,7 +1275,7 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc // Must be checked after SLIC marker because of the same *signature values else if (*signature == INTEL_MICROCODE_HEADER_VERSION_1) return ffsParser->parseIntelMicrocodeHeader(store, localOffset, parent, index); - + msg(usprintf("parseStoreHeader: don't know how to parse a header with signature %08Xh", *signature), parent); return U_SUCCESS; } @@ -1285,13 +1285,13 @@ USTATUS NvramParser::parseFdcStoreBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Get item data const UByteArray data = model->body(index); - + // Get local offset UINT32 localOffset = (UINT32)model->header(index).size(); - + // The body is a firmware volume with either a VSS or VSS2 store UModelIndex volumeIndex; USTATUS status = ffsParser->parseVolumeHeader(data, localOffset, index, volumeIndex); @@ -1299,7 +1299,7 @@ USTATUS NvramParser::parseFdcStoreBody(const UModelIndex & index) msg(usprintf("%s: store can't be parsed as FDC store", __FUNCTION__), index); return U_SUCCESS; } - + // Determine if it's a VSS or VSS2 store inside UByteArray store = model->body(volumeIndex); if ((UINT32)store.size() >= sizeof(UINT32) && *(const UINT32*)store.constData() == NVRAM_VSS_STORE_SIGNATURE) { @@ -1320,7 +1320,7 @@ USTATUS NvramParser::parseFdcStoreBody(const UModelIndex & index) msg(usprintf("%s: internal volume can't be parsed as VSS/VSS2 store", __FUNCTION__), index); return U_SUCCESS; } - + } USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignment) @@ -1328,7 +1328,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Obtain required information from parent volume UINT8 emptyByte = 0xFF; UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume); @@ -1337,35 +1337,35 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); emptyByte = pdata->emptyByte; } - + // Get local offset UINT32 localOffset = (UINT32)model->header(index).size(); - + // Get item data const UByteArray data = model->body(index); - + // Check that the is enough space for variable header const UINT32 dataSize = (UINT32)data.size(); if (dataSize < sizeof(VSS_VARIABLE_HEADER)) { msg(usprintf("%s: store body is too small even for VSS variable header", __FUNCTION__), index); return U_SUCCESS; } - + UINT32 offset = 0; - + // Parse all variables while (1) { bool isInvalid = true; bool isAuthenticated = false; bool isAppleCrc32 = false; bool isIntelSpecial = false; - + UINT32 storedCrc32 = 0; UINT32 calculatedCrc32 = 0; UINT64 monotonicCounter = 0; EFI_TIME timestamp = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; UINT32 pubKeyIndex = 0; - + UINT8 subtype = 0; UString name; UString text; @@ -1373,12 +1373,12 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen CHAR16* variableName = (CHAR16*)L""; UByteArray header; UByteArray body; - + UINT32 unparsedSize = dataSize - offset; - + // Get variable header const VSS_VARIABLE_HEADER* variableHeader = (const VSS_VARIABLE_HEADER*)(data.constData() + offset); - + // Check variable header to fit in still unparsed data UINT32 variableSize = 0; if (unparsedSize >= sizeof(VSS_VARIABLE_HEADER) @@ -1394,21 +1394,21 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen variableSize = sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize + appleVariableHeader->DataSize; variableGuid = (EFI_GUID*)&appleVariableHeader->VendorGuid; variableName = (CHAR16*)(appleVariableHeader + 1); - + header = data.mid(offset, sizeof(VSS_APPLE_VARIABLE_HEADER) + appleVariableHeader->NameSize); body = data.mid(offset + header.size(), appleVariableHeader->DataSize); - + // Calculate CRC32 of the variable data storedCrc32 = appleVariableHeader->DataCrc32; calculatedCrc32 = (UINT32)crc32(0, (const UINT8*)body.constData(), (uInt)body.size()); } } - + // Authenticated variable else if ((variableHeader->Attributes & NVRAM_VSS_VARIABLE_AUTHENTICATED_WRITE_ACCESS) - || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) - || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPEND_WRITE) - || (variableHeader->NameSize == 0 && variableHeader->DataSize == 0)) { // If both NameSize and DataSize are zeros, it's auth variable with zero montonic counter + || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + || (variableHeader->Attributes & NVRAM_VSS_VARIABLE_APPEND_WRITE) + || (variableHeader->NameSize == 0 && variableHeader->DataSize == 0)) { // If both NameSize and DataSize are zeros, it's auth variable with zero montonic counter isAuthenticated = true; if (unparsedSize < sizeof(VSS_AUTH_VARIABLE_HEADER)) { variableSize = 0; @@ -1418,65 +1418,65 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen variableSize = sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize + authVariableHeader->DataSize; variableGuid = (EFI_GUID*)&authVariableHeader->VendorGuid; variableName = (CHAR16*)(authVariableHeader + 1); - + header = data.mid(offset, sizeof(VSS_AUTH_VARIABLE_HEADER) + authVariableHeader->NameSize); body = data.mid(offset + header.size(), authVariableHeader->DataSize); - + monotonicCounter = authVariableHeader->MonotonicCounter; timestamp = authVariableHeader->Timestamp; pubKeyIndex = authVariableHeader->PubKeyIndex; } } - + // Intel special variable else if (variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_VALID - || variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_INVALID) { + || variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_INVALID) { isIntelSpecial = true; const VSS_INTEL_VARIABLE_HEADER* intelVariableHeader = (const VSS_INTEL_VARIABLE_HEADER*)variableHeader; variableSize = intelVariableHeader->TotalSize; variableGuid = (EFI_GUID*)&intelVariableHeader->VendorGuid; variableName = (CHAR16*)(intelVariableHeader + 1); - + UINT32 i = 0; while (variableName[i] != 0) ++i; - + i = sizeof(VSS_INTEL_VARIABLE_HEADER) + 2 * (i + 1); i = i < variableSize ? i : variableSize; - + header = data.mid(offset, i); body = data.mid(offset + header.size(), variableSize - i); } - + // Normal VSS variable else { variableSize = sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize + variableHeader->DataSize; variableGuid = (EFI_GUID*)&variableHeader->VendorGuid; variableName = (CHAR16*)(variableHeader + 1); - + header = data.mid(offset, sizeof(VSS_VARIABLE_HEADER) + variableHeader->NameSize); body = data.mid(offset + header.size(), variableHeader->DataSize); } - + // Check variable state if (variableHeader->State == NVRAM_VSS_INTEL_VARIABLE_VALID || variableHeader->State == NVRAM_VSS_VARIABLE_ADDED || variableHeader->State == NVRAM_VSS_VARIABLE_HEADER_VALID) { isInvalid = false; } - + // Check variable size if (variableSize > unparsedSize) { variableSize = 0; } } - + // Can't parse further, add the last element and break the loop if (!variableSize) { // Check if the data left is a free space or a padding UByteArray padding = data.mid(offset, unparsedSize); // Get info - UString info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)padding.size(), (UINT32)padding.size()); + if (padding.count(emptyByte) == padding.size()) { // Free space // Add tree item model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); @@ -1487,16 +1487,16 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen msg(usprintf("%s: store can't be parsed as VSS store", __FUNCTION__), index); return U_SUCCESS; } - + // Add tree item model->addItem(localOffset + offset, Types::Padding, getPaddingType(padding), UString("Padding"), UString(), info, UByteArray(), padding, UByteArray(), Fixed, index); } - + return U_SUCCESS; } - + UString info; - + // Rename invalid variables if (isInvalid || !variableGuid) { isInvalid = true; @@ -1505,35 +1505,35 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen else { // Add GUID and text for valid variables name = guidToUString(readUnaligned(variableGuid)); info += UString("Variable GUID: ") + guidToUString(readUnaligned(variableGuid), false) + UString("\n"); - + #if QT_VERSION_MAJOR >= 6 text = UString::fromUtf16((char16_t *)variableName); #else text = UString::fromUtf16(variableName); #endif } - + // Add info info += usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nState: %02Xh\nReserved: %02Xh\nAttributes: %08Xh (", - variableSize, variableSize, - header.size(), header.size(), - body.size(), body.size(), - variableHeader->State, - variableHeader->Reserved, - variableHeader->Attributes) + vssAttributesToUString(variableHeader->Attributes) + UString(")"); - + variableSize, variableSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + variableHeader->State, + variableHeader->Reserved, + variableHeader->Attributes) + vssAttributesToUString(variableHeader->Attributes) + UString(")"); + // Set subtype and add related info if (isInvalid) subtype = Subtypes::InvalidVssEntry; else if (isAuthenticated) { subtype = Subtypes::AuthVssEntry; info += usprintf("\nMonotonic counter: %" PRIX64 "h\nTimestamp: ", monotonicCounter) + efiTimeToUString(timestamp) - + usprintf("\nPubKey index: %u", pubKeyIndex); + + usprintf("\nPubKey index: %u", pubKeyIndex); } else if (isAppleCrc32) { subtype = Subtypes::AppleVssEntry; info += usprintf("\nData checksum: %08Xh", storedCrc32) + - (storedCrc32 != calculatedCrc32 ? usprintf(", invalid, should be %08Xh", calculatedCrc32) : UString(", valid")); + (storedCrc32 != calculatedCrc32 ? usprintf(", invalid, should be %08Xh", calculatedCrc32) : UString(", valid")); } else if (isIntelSpecial) { subtype = Subtypes::IntelVssEntry; @@ -1541,19 +1541,19 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index, UINT8 alignmen else { subtype = Subtypes::StandardVssEntry; } - + // Add tree item model->addItem(localOffset + offset, Types::VssEntry, subtype, name, text, info, header, body, UByteArray(), Fixed, index); - + // Apply alignment, if needed if (alignment) { variableSize = ((variableSize + alignment - 1) & (~(alignment - 1))); } - + // Move to next variable offset += variableSize; } - + return U_SUCCESS; } @@ -1562,32 +1562,32 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Get local offset UINT32 localOffset = (UINT32)model->header(index).size(); - + // Get item data const UByteArray data = model->body(index); - + // Check that the is enough space for variable header const UINT32 storeDataSize = (UINT32)data.size(); UINT32 offset = 0; - + // Parse all variables while (1) { UINT32 unparsedSize = storeDataSize - offset; UINT32 variableSize = 0; - + // Get nameSize and name of the variable UINT8 nameSize = *(UINT8*)(data.constData() + offset); bool valid = !(nameSize & 0x80); // Last bit is a validity bit, 0 means valid nameSize &= 0x7F; - + // Check sanity if (unparsedSize >= nameSize + sizeof(UINT8)) { variableSize = nameSize + sizeof(UINT8); } - + UByteArray name; if (variableSize) { name = data.mid(offset + sizeof(UINT8), nameSize); @@ -1595,23 +1595,23 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) if (nameSize == 3 && name[0] == 'E' && name[1] == 'O' && name[2] == 'F') { // There is no data afterward, add EOF variable and free space and return UByteArray header = data.mid(offset, sizeof(UINT8) + nameSize); - UString info = usprintf("Full size: %Xh (%u)", header.size(), header.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)header.size(), (UINT32)header.size()); + // Add EOF tree item model->addItem(localOffset + offset, Types::FsysEntry, Subtypes::NormalFsysEntry, UString("EOF"), UString(), info, header, UByteArray(), UByteArray(), Fixed, index); - + // Add free space - offset += header.size(); + offset += (UINT32)header.size(); UByteArray body = data.mid(offset); - info = usprintf("Full size: %Xh (%u)", body.size(), body.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); + // Add free space tree item model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - + return U_SUCCESS; } } - + // Get dataSize and data of the variable const UINT16 dataSize = *(UINT16*)(data.constData() + offset + sizeof(UINT8) + nameSize); if (unparsedSize >= sizeof(UINT8) + nameSize + sizeof(UINT16) + dataSize) { @@ -1620,34 +1620,34 @@ USTATUS NvramParser::parseFsysStoreBody(const UModelIndex & index) else { // Last variable is bad, add the rest as padding and return UByteArray body = data.mid(offset); - UString info = usprintf("Full size: %Xh (%u)", body.size(), body.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); + // Add padding tree item model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - + // Show message msg(usprintf("%s: next variable appears too big, added as padding", __FUNCTION__), index); - + return U_SUCCESS; } - + // Construct header and body UByteArray header = data.mid(offset, sizeof(UINT8) + nameSize + sizeof(UINT16)); UByteArray body = data.mid(offset + sizeof(UINT8) + nameSize + sizeof(UINT16), dataSize); - + // Add info UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)", - variableSize, variableSize, - header.size(), header.size(), - body.size(), body.size()); - + variableSize, variableSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size()); + // Add tree item model->addItem(localOffset + offset, Types::FsysEntry, valid ? Subtypes::NormalFsysEntry : Subtypes::InvalidFsysEntry, UString(name.constData()), UString(), info, header, body, UByteArray(), Fixed, index); - + // Move to next variable offset += variableSize; } - + return U_SUCCESS; } @@ -1656,7 +1656,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Obtain required information from parent volume UINT8 emptyByte = 0xFF; UModelIndex parentVolumeIndex = model->findParentOfType(index, Types::Volume); @@ -1665,20 +1665,20 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData(); emptyByte = pdata->emptyByte; } - + // Get local offset UINT32 localOffset = (UINT32)model->header(index).size(); - + // Get item data const UByteArray data = model->body(index); - + // Check that the is enough space for entry header const UINT32 storeDataSize = (UINT32)data.size(); UINT32 offset = 0; - + std::map guidMap; std::map nameMap; - + // Parse all entries UINT32 unparsedSize = storeDataSize; while (unparsedSize) { @@ -1689,15 +1689,15 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) UByteArray body; UINT8 subtype; UINT8 calculated; - + const EVSA_ENTRY_HEADER* entryHeader = (const EVSA_ENTRY_HEADER*)(data.constData() + offset); - + // Check entry size variableSize = sizeof(EVSA_ENTRY_HEADER); if (unparsedSize < variableSize || unparsedSize < entryHeader->Size) { body = data.mid(offset); - info = usprintf("Full size: %Xh (%u)", body.size(), body.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); + if (body.count(emptyByte) == body.size()) { // Free space // Add free space tree item model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); @@ -1705,17 +1705,17 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) else { // Add padding tree item UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - + // Show message msg(usprintf("%s: variable parsing failed, the rest of unparsed store added as padding", __FUNCTION__), itemIndex); } break; } variableSize = entryHeader->Size; - + // Recalculate entry checksum calculated = calculateChecksum8(((const UINT8*)entryHeader) + 2, entryHeader->Size - 2); - + // GUID entry if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID1 || entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID2) { @@ -1724,45 +1724,47 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) body = data.mid(offset + sizeof(EVSA_GUID_ENTRY), guidHeader->Header.Size - sizeof(EVSA_GUID_ENTRY)); EFI_GUID guid = *(EFI_GUID*)body.constData(); name = guidToUString(guid); - info = UString("GUID: ") + guidToUString(guid, false) + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", - variableSize, variableSize, - header.size(), header.size(), - body.size(), body.size(), - guidHeader->Header.Type, - guidHeader->Header.Checksum) - + (guidHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) - + usprintf("\nGuidId: %04Xh", guidHeader->GuidId); + info = UString("GUID: ") + guidToUString(guid, false) + + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", + variableSize, variableSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + guidHeader->Header.Type, + guidHeader->Header.Checksum) + + (guidHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + + usprintf("\nGuidId: %04Xh", guidHeader->GuidId); subtype = Subtypes::GuidEvsaEntry; guidMap.insert(std::pair(guidHeader->GuidId, guid)); } // Name entry else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME1 || - entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME2) { + entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME2) { const EVSA_NAME_ENTRY* nameHeader = (const EVSA_NAME_ENTRY*)entryHeader; header = data.mid(offset, sizeof(EVSA_NAME_ENTRY)); body = data.mid(offset + sizeof(EVSA_NAME_ENTRY), nameHeader->Header.Size - sizeof(EVSA_NAME_ENTRY)); - + #if QT_VERSION_MAJOR >= 6 name = UString::fromUtf16((const char16_t *)body.constData()); #else name = UString::fromUtf16((const CHAR16*)body.constData()); #endif - - info = UString("Name: ") + name + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", - variableSize, variableSize, - header.size(), header.size(), - body.size(), body.size(), - nameHeader->Header.Type, - nameHeader->Header.Checksum) - + (nameHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) - + usprintf("\nVarId: %04Xh", nameHeader->VarId); + + info = UString("Name: ") + name + + usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", + variableSize, variableSize, + (UINT32)header.size(), (UINT32)header.size(), + (UINT32)body.size(), (UINT32)body.size(), + nameHeader->Header.Type, + nameHeader->Header.Checksum) + + (nameHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + + usprintf("\nVarId: %04Xh", nameHeader->VarId); subtype = Subtypes::NameEvsaEntry; nameMap.insert(std::pair(nameHeader->VarId, name)); } // Data entry else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA1 || - entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA2 || - entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) { + entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA2 || + entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA_INVALID) { const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)entryHeader; // Check for extended header UINT32 headerSize = sizeof(EVSA_DATA_ENTRY); @@ -1773,29 +1775,29 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) dataSize = dataHeaderExtended->DataSize; variableSize = headerSize + dataSize; } - + header = data.mid(offset, headerSize); body = data.mid(offset + headerSize, dataSize); name = UString("Data"); info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nType: %02Xh\nChecksum: %02Xh", - variableSize, variableSize, - headerSize, headerSize, - dataSize, dataSize, - dataHeader->Header.Type, - dataHeader->Header.Checksum) - + (dataHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) - + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (", - dataHeader->VarId, - dataHeader->GuidId, - dataHeader->Attributes) - + evsaAttributesToUString(dataHeader->Attributes) + UString(")"); + variableSize, variableSize, + headerSize, headerSize, + dataSize, dataSize, + dataHeader->Header.Type, + dataHeader->Header.Checksum) + + (dataHeader->Header.Checksum != calculated ? usprintf(", invalid, should be %02Xh", calculated) : UString(", valid")) + + usprintf("\nVarId: %04Xh\nGuidId: %04Xh\nAttributes: %08Xh (", + dataHeader->VarId, + dataHeader->GuidId, + dataHeader->Attributes) + + evsaAttributesToUString(dataHeader->Attributes) + UString(")"); subtype = Subtypes::DataEvsaEntry; } // Unknown entry or free space else { body = data.mid(offset); - info = usprintf("Full size: %Xh (%u)", body.size(), body.size()); - + info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); + if (body.count(emptyByte) == body.size()) { // Free space // Add free space tree item model->addItem(localOffset + offset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); @@ -1803,25 +1805,25 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) else { // Add padding tree item UModelIndex itemIndex = model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - + // Show message msg(usprintf("%s: unknown variable of type %02Xh found at offset %Xh, the rest of unparsed store added as padding", __FUNCTION__, entryHeader->Type, offset), itemIndex); } break; } - + // Add tree item model->addItem(localOffset + offset, Types::EvsaEntry, subtype, name, UString(), info, header, body, UByteArray(), Fixed, index); - + // Move to next variable offset += variableSize; unparsedSize = storeDataSize - offset; } - + // Reparse all data variables to detect invalid ones and assign name and test to valid ones for (int i = 0; i < model->rowCount(index); i++) { UModelIndex current = index.model()->index(i, 0, index); - + if (model->subtype(current) == Subtypes::DataEvsaEntry) { UByteArray header = model->header(current); const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)header.constData(); @@ -1831,7 +1833,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) UString name; if (nameMap.count(dataHeader->VarId)) name = nameMap[dataHeader->VarId]; - + // Check for variable validity if (guid.isEmpty() && name.isEmpty()) { // Both name and guid aren't found model->setSubtype(current, Subtypes::InvalidEvsaEntry); @@ -1861,7 +1863,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index) } } } - + return U_SUCCESS; } @@ -1871,69 +1873,69 @@ USTATUS NvramParser::parseFlashMapBody(const UModelIndex & index) // Sanity check if (!index.isValid()) return U_INVALID_PARAMETER; - + // Get parsing data for the current item UINT32 localOffset = (UINT32)model->header(index).size(); const UByteArray data = model->body(index); - - + + const UINT32 dataSize = (UINT32)data.size(); UINT32 offset = 0; UINT32 unparsedSize = dataSize; // Parse all entries while (unparsedSize) { const PHOENIX_FLASH_MAP_ENTRY* entryHeader = (const PHOENIX_FLASH_MAP_ENTRY*)(data.constData() + offset); - + // Check entry size if (unparsedSize < sizeof(PHOENIX_FLASH_MAP_ENTRY)) { // Last variable is bad, add the rest as padding and return UByteArray body = data.mid(offset); - UString info = usprintf("Full size: %Xh (%u)", body.size(), body.size()); - + UString info = usprintf("Full size: %Xh (%u)", (UINT32)body.size(), (UINT32)body.size()); + // Add padding tree item model->addItem(localOffset + offset, Types::Padding, getPaddingType(body), UString("Padding"), UString(), info, UByteArray(), body, UByteArray(), Fixed, index); - + // Show message if (unparsedSize < entryHeader->Size) msg(usprintf("%s: next entry appears too big, added as padding", __FUNCTION__), index); - + break; } - + UString name = guidToUString(entryHeader->Guid); - + // Construct header UByteArray header = data.mid(offset, sizeof(PHOENIX_FLASH_MAP_ENTRY)); - + // Add info UString info = UString("Entry GUID: ") + guidToUString(entryHeader->Guid, false) + - usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n" - "Entry type: %04Xh\nData type: %04Xh\nMemory address: %08llXh\nSize: %08Xh\nOffset: %08Xh", - entryHeader->EntryType, - entryHeader->DataType, - (unsigned long long)entryHeader->PhysicalAddress, - entryHeader->Size, - entryHeader->Offset); - + usprintf("\nFull size: 24h (36)\nHeader size: 24h (36)\nBody size: 0h (0)\n" + "Entry type: %04Xh\nData type: %04Xh\nMemory address: %08llXh\nSize: %08Xh\nOffset: %08Xh", + entryHeader->EntryType, + entryHeader->DataType, + (unsigned long long)entryHeader->PhysicalAddress, + entryHeader->Size, + entryHeader->Offset); + // Determine subtype UINT8 subtype = 0; switch (entryHeader->DataType) { - case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_VOLUME: - subtype = Subtypes::VolumeFlashMapEntry; - break; - case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_DATA_BLOCK: - subtype = Subtypes::DataFlashMapEntry; - break; + case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_VOLUME: + subtype = Subtypes::VolumeFlashMapEntry; + break; + case NVRAM_PHOENIX_FLASH_MAP_ENTRY_TYPE_DATA_BLOCK: + subtype = Subtypes::DataFlashMapEntry; + break; } - + // Add tree item model->addItem(localOffset + offset, Types::FlashMapEntry, subtype, name, flashMapGuidToUString(entryHeader->Guid), info, header, UByteArray(), UByteArray(), Fixed, index); - + // Move to next variable offset += sizeof(PHOENIX_FLASH_MAP_ENTRY); unparsedSize = dataSize - offset; } - + return U_SUCCESS; } #endif // U_ENABLE_NVRAM_PARSING_SUPPORT diff --git a/common/peimage.cpp b/common/peimage.cpp index c3dfe9b..b2d39c8 100644 --- a/common/peimage.cpp +++ b/common/peimage.cpp @@ -1,35 +1,35 @@ /* peimage.cpp - -Copyright (c) 2015, 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2015, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "peimage.h" UString machineTypeToUString(UINT16 machineType) { switch (machineType) { - case EFI_IMAGE_FILE_MACHINE_AMD64: return UString("x86-64"); - case EFI_IMAGE_FILE_MACHINE_ARM: return UString("ARM"); - case EFI_IMAGE_FILE_MACHINE_ARMNT: return UString("ARMv7"); - case EFI_IMAGE_FILE_MACHINE_APPLE_ARM: return UString("Apple ARM"); - case EFI_IMAGE_FILE_MACHINE_AARCH64: return UString("AArch64"); - case EFI_IMAGE_FILE_MACHINE_EBC: return UString("EBC"); - case EFI_IMAGE_FILE_MACHINE_I386: return UString("x86"); - case EFI_IMAGE_FILE_MACHINE_IA64: return UString("IA64"); - case EFI_IMAGE_FILE_MACHINE_POWERPC: return UString("PowerPC"); - case EFI_IMAGE_FILE_MACHINE_POWERPCFP: return UString("PowerPC FP"); - case EFI_IMAGE_FILE_MACHINE_THUMB: return UString("ARM Thumb"); - case EFI_IMAGE_FILE_MACHINE_RISCV32: return UString("RISC-V 32-bit"); - case EFI_IMAGE_FILE_MACHINE_RISCV64: return UString("RISC-V 64-bit"); - case EFI_IMAGE_FILE_MACHINE_RISCV128: return UString("RISC-V 128-bit"); - default: return usprintf("Unknown (%04Xh)", machineType); + case EFI_IMAGE_FILE_MACHINE_AMD64: return UString("x86-64"); + case EFI_IMAGE_FILE_MACHINE_ARM: return UString("ARM"); + case EFI_IMAGE_FILE_MACHINE_ARMNT: return UString("ARMv7"); + case EFI_IMAGE_FILE_MACHINE_APPLE_ARM: return UString("Apple ARM"); + case EFI_IMAGE_FILE_MACHINE_AARCH64: return UString("AArch64"); + case EFI_IMAGE_FILE_MACHINE_EBC: return UString("EBC"); + case EFI_IMAGE_FILE_MACHINE_I386: return UString("x86"); + case EFI_IMAGE_FILE_MACHINE_IA64: return UString("IA64"); + case EFI_IMAGE_FILE_MACHINE_POWERPC: return UString("PowerPC"); + case EFI_IMAGE_FILE_MACHINE_POWERPCFP: return UString("PowerPC FP"); + case EFI_IMAGE_FILE_MACHINE_THUMB: return UString("ARM Thumb"); + case EFI_IMAGE_FILE_MACHINE_RISCV32: return UString("RISC-V 32-bit"); + case EFI_IMAGE_FILE_MACHINE_RISCV64: return UString("RISC-V 64-bit"); + case EFI_IMAGE_FILE_MACHINE_RISCV128: return UString("RISC-V 128-bit"); + default: return usprintf("Unknown (%04Xh)", machineType); } -} \ No newline at end of file +} diff --git a/common/treeitem.cpp b/common/treeitem.cpp index 3b2e09c..3939c0b 100644 --- a/common/treeitem.cpp +++ b/common/treeitem.cpp @@ -1,38 +1,38 @@ /* treeitem.cpp - -Copyright (c) 2015, 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2015, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "treeitem.h" #include "types.h" TreeItem::TreeItem(const UINT32 offset, const UINT8 type, const UINT8 subtype, - const UString & name, const UString & text, const UString & info, - const UByteArray & header, const UByteArray & body, const UByteArray & tail, - const bool fixed, const bool compressed, - TreeItem *parent) : - itemOffset(offset), - itemAction(Actions::NoAction), - itemType(type), - itemSubtype(subtype), - itemMarking(0), - itemName(name), - itemText(text), - itemInfo(info), - itemHeader(header), - itemBody(body), - itemTail(tail), - itemFixed(fixed), - itemCompressed(compressed), - parentItem(parent) + const UString & name, const UString & text, const UString & info, + const UByteArray & header, const UByteArray & body, const UByteArray & tail, + const bool fixed, const bool compressed, + TreeItem *parent) : +itemOffset(offset), +itemAction(Actions::NoAction), +itemType(type), +itemSubtype(subtype), +itemMarking(0), +itemName(name), +itemText(text), +itemInfo(info), +itemHeader(header), +itemBody(body), +itemTail(tail), +itemFixed(fixed), +itemCompressed(compressed), +parentItem(parent) { } @@ -66,18 +66,18 @@ UString TreeItem::data(int column) const { switch (column) { - case 0: // Name - return itemName; - case 1: // Action - return actionTypeToUString(itemAction); - case 2: // Type - return itemTypeToUString(itemType); - case 3: // Subtype - return itemSubtypeToUString(itemType, itemSubtype); - case 4: // Text - return itemText; - default: - return UString(); + case 0: // Name + return itemName; + case 1: // Action + return actionTypeToUString(itemAction); + case 2: // Type + return itemTypeToUString(itemType); + case 3: // Subtype + return itemSubtypeToUString(itemType, itemSubtype); + case 4: // Text + return itemText; + default: + return UString(); } } @@ -98,4 +98,4 @@ TreeItem* TreeItem::child(int row) std::list::iterator child = childItems.begin(); std::advance(child, row); return *child; -} \ No newline at end of file +} diff --git a/common/treemodel.cpp b/common/treemodel.cpp index d7cb47d..9715a79 100644 --- a/common/treemodel.cpp +++ b/common/treemodel.cpp @@ -1,15 +1,15 @@ /* treemodel.cpp - -Copyright (c) 2015, 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, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + Copyright (c) 2015, 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, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include "treemodel.h" @@ -20,9 +20,9 @@ QVariant TreeModel::data(const UModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); - + TreeItem *item = static_cast(index.internalPointer()); - + if (role == Qt::DisplayRole) { return item->data(index.column()).toLocal8Bit(); } @@ -36,7 +36,7 @@ QVariant TreeModel::data(const UModelIndex &index, int role) const else if (role == Qt::UserRole) { return item->info().toLocal8Bit(); } - + return QVariant(); } @@ -44,23 +44,23 @@ Qt::ItemFlags TreeModel::flags(const UModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; - + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QVariant TreeModel::headerData(int section, Qt::Orientation orientation, - int role) const + int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { - case 0: return tr("Name"); - case 1: return tr("Action"); - case 2: return tr("Type"); - case 3: return tr("Subtype"); - case 4: return tr("Text"); + case 0: return tr("Name"); + case 1: return tr("Action"); + case 2: return tr("Type"); + case 3: return tr("Subtype"); + case 4: return tr("Text"); } } - + return QVariant(); } #else @@ -68,12 +68,12 @@ UString TreeModel::data(const UModelIndex &index, int role) const { if (!index.isValid()) return UString(); - + if (role != 0 && role != 0x0100) return UString(); - + TreeItem *item = static_cast(index.internalPointer()); - + if (role == 0) return item->data(index.column()); else @@ -81,19 +81,19 @@ UString TreeModel::data(const UModelIndex &index, int role) const } UString TreeModel::headerData(int section, int orientation, - int role) const + int role) const { if (orientation == 1 && role == 0) { switch (section) { - case 0: return UString("Name"); - case 1: return UString("Action"); - case 2: return UString("Type"); - case 3: return UString("Subtype"); - case 4: return UString("Text"); + case 0: return UString("Name"); + case 1: return UString("Action"); + case 2: return UString("Type"); + case 3: return UString("Subtype"); + case 4: return UString("Text"); } } - + return UString(); } #endif @@ -110,14 +110,14 @@ UModelIndex TreeModel::index(int row, int column, const UModelIndex &parent) con { if (!hasIndex(row, column, parent)) return UModelIndex(); - + TreeItem *parentItem; - + if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); - + TreeItem *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); @@ -129,16 +129,16 @@ UModelIndex TreeModel::parent(const UModelIndex &index) const { if (!index.isValid()) return UModelIndex(); - + TreeItem *childItem = static_cast(index.internalPointer()); if (childItem == rootItem) return UModelIndex(); - + TreeItem *parentItem = childItem->parent(); - + if (parentItem == rootItem) return UModelIndex(); - + return createIndex(parentItem->row(), 0, parentItem); } @@ -147,12 +147,12 @@ int TreeModel::rowCount(const UModelIndex &parent) const TreeItem *parentItem; if (parent.column() > 0) return 0; - + if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); - + return parentItem->childCount(); } @@ -161,7 +161,7 @@ UINT32 TreeModel::base(const UModelIndex ¤t) const // TODO: rewrite this as loop if we ever see an image that is too deep for this naive implementation if (!current.isValid()) return 0; - + UModelIndex parent = current.parent(); if (!parent.isValid()) return offset(current); @@ -302,24 +302,24 @@ void TreeModel::setFixed(const UModelIndex &index, const bool fixed) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setFixed(fixed); - + if (!item->parent()) return; - + if (fixed) { // Special handling for uncompressed to compressed boundary if (item->compressed() && item->parent()->compressed() == FALSE) { item->setFixed(item->parent()->fixed()); return; } - + // Propagate fixed flag until root setFixed(index.parent(), true); } - + emit dataChanged(index, index); } @@ -327,10 +327,10 @@ void TreeModel::setCompressed(const UModelIndex &index, const bool compressed) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setCompressed(compressed); - + emit dataChanged(index, index); } @@ -345,10 +345,10 @@ void TreeModel::setMarking(const UModelIndex &index, const UINT8 marking) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setMarking(marking); - + emit dataChanged(index, index); } @@ -356,7 +356,7 @@ void TreeModel::setOffset(const UModelIndex &index, const UINT32 offset) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setOffset(offset); emit dataChanged(index, index); @@ -366,7 +366,7 @@ void TreeModel::setType(const UModelIndex &index, const UINT8 data) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setType(data); emit dataChanged(index, index); @@ -376,7 +376,7 @@ void TreeModel::setSubtype(const UModelIndex & index, const UINT8 subtype) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setSubtype(subtype); emit dataChanged(index, index); @@ -386,7 +386,7 @@ void TreeModel::setName(const UModelIndex &index, const UString &data) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setName(data); emit dataChanged(index, index); @@ -396,7 +396,7 @@ void TreeModel::setText(const UModelIndex &index, const UString &data) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setText(data); emit dataChanged(index, index); @@ -406,7 +406,7 @@ void TreeModel::setInfo(const UModelIndex &index, const UString &data) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setInfo(data); emit dataChanged(index, index); @@ -416,7 +416,7 @@ void TreeModel::addInfo(const UModelIndex &index, const UString &data, const boo { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->addInfo(data, append); emit dataChanged(index, index); @@ -426,7 +426,7 @@ void TreeModel::setAction(const UModelIndex &index, const UINT8 action) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setAction(action); emit dataChanged(index, index); @@ -436,7 +436,7 @@ UByteArray TreeModel::parsingData(const UModelIndex &index) const { if (!index.isValid()) return UByteArray(); - + TreeItem *item = static_cast(index.internalPointer()); return item->parsingData(); } @@ -445,7 +445,7 @@ bool TreeModel::hasEmptyParsingData(const UModelIndex &index) const { if (!index.isValid()) return true; - + TreeItem *item = static_cast(index.internalPointer()); return item->hasEmptyParsingData(); } @@ -454,7 +454,7 @@ void TreeModel::setParsingData(const UModelIndex &index, const UByteArray &data) { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setParsingData(data); emit dataChanged(this->index(0, 0), index); @@ -464,7 +464,7 @@ UByteArray TreeModel::uncompressedData(const UModelIndex &index) const { if (!index.isValid()) return UByteArray(); - + TreeItem *item = static_cast(index.internalPointer()); return item->uncompressedData(); } @@ -473,7 +473,7 @@ bool TreeModel::hasEmptyUncompressedData(const UModelIndex &index) const { if (!index.isValid()) return true; - + TreeItem *item = static_cast(index.internalPointer()); return item->hasEmptyUncompressedData(); } @@ -482,22 +482,22 @@ void TreeModel::setUncompressedData(const UModelIndex &index, const UByteArray & { if (!index.isValid()) return; - + TreeItem *item = static_cast(index.internalPointer()); item->setUncompressedData(data); emit dataChanged(this->index(0, 0), index); } UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT8 subtype, - const UString & name, const UString & text, const UString & info, - const UByteArray & header, const UByteArray & body, const UByteArray & tail, - const ItemFixedState fixed, - const UModelIndex & parent, const UINT8 mode) + const UString & name, const UString & text, const UString & info, + const UByteArray & header, const UByteArray & body, const UByteArray & tail, + const ItemFixedState fixed, + const UModelIndex & parent, const UINT8 mode) { TreeItem *item = 0; TreeItem *parentItem = 0; int parentColumn = 0; - + if (!parent.isValid()) parentItem = rootItem; else @@ -512,9 +512,9 @@ UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT parentColumn = parent.column(); } } - + TreeItem *newItem = new TreeItem(offset, type, subtype, name, text, info, header, body, tail, Movable, this->compressed(parent), parentItem); - + if (mode == CREATE_MODE_APPEND) { emit layoutAboutToBeChanged(); parentItem->appendChild(newItem); @@ -535,9 +535,9 @@ UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT delete newItem; return UModelIndex(); } - + emit layoutChanged(); - + UModelIndex created = createIndex(newItem->row(), parentColumn, newItem); setFixed(created, (bool)fixed); // Non-trivial logic requires additional call return created; @@ -547,17 +547,17 @@ UModelIndex TreeModel::findParentOfType(const UModelIndex& index, UINT8 type) co { if (!index.isValid() || !index.parent().isValid()) return UModelIndex(); - + TreeItem *item; UModelIndex parent = index.parent(); - + for (item = static_cast(parent.internalPointer()); - item != NULL && item != rootItem && item->type() != type; - item = static_cast(parent.internalPointer())) - parent = parent.parent(); + item != NULL && item != rootItem && item->type() != type; + item = static_cast(parent.internalPointer())) + parent = parent.parent(); if (item != NULL && item != rootItem) return parent; - + return UModelIndex(); } @@ -565,30 +565,30 @@ UModelIndex TreeModel::findLastParentOfType(const UModelIndex& index, UINT8 type { if (!index.isValid()) return UModelIndex(); - + UModelIndex lastParentOfType = findParentOfType(index, type); - + if (!lastParentOfType.isValid()) return UModelIndex(); - + UModelIndex currentParentOfType = findParentOfType(lastParentOfType, type); while (currentParentOfType.isValid()) { lastParentOfType = currentParentOfType; currentParentOfType = findParentOfType(lastParentOfType, type); } - + return lastParentOfType; } UModelIndex TreeModel::findByBase(UINT32 base) const { UModelIndex parentIndex = index(0,0); - + goDeeper: int n = rowCount(parentIndex); for (int i = 0; i < n; i++) { UModelIndex currentIndex = parentIndex.model()->index(i, 0, parentIndex); - + UINT32 currentBase = this->base(currentIndex); UINT32 fullSize = (UINT32)(header(currentIndex).size() + body(currentIndex).size() + tail(currentIndex).size()); if ((compressed(currentIndex) == false || (compressed(currentIndex) == true && compressed(currentIndex.parent()) == false)) // Base is meaningful only for true uncompressed items @@ -598,6 +598,6 @@ goDeeper: goto goDeeper; } } - + return (parentIndex == index(0, 0) ? UModelIndex() : parentIndex); } diff --git a/common/types.cpp b/common/types.cpp index 4854748..c1fac7e 100755 --- a/common/types.cpp +++ b/common/types.cpp @@ -1,14 +1,14 @@ /* types.cpp - -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 -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. -*/ + + 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 + 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. + */ #include "ustring.h" #include "types.h" @@ -18,202 +18,202 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. UString regionTypeToUString(const UINT8 type) { switch (type) { - case Subtypes::DescriptorRegion: return UString("Descriptor"); - case Subtypes::BiosRegion: return UString("BIOS"); - case Subtypes::MeRegion: return UString("ME"); - case Subtypes::GbeRegion: return UString("GbE"); - case Subtypes::PdrRegion: return UString("PDR"); - case Subtypes::DevExp1Region: return UString("DevExp1"); - case Subtypes::Bios2Region: return UString("BIOS2"); - case Subtypes::MicrocodeRegion: return UString("Microcode"); - case Subtypes::EcRegion: return UString("EC"); - case Subtypes::DevExp2Region: return UString("DevExp2"); - case Subtypes::IeRegion: return UString("IE"); - case Subtypes::Tgbe1Region: return UString("10GbE1"); - case Subtypes::Tgbe2Region: return UString("10GbE2"); - case Subtypes::Reserved1Region: return UString("Reserved1"); - case Subtypes::Reserved2Region: return UString("Reserved2"); - case Subtypes::PttRegion: return UString("PTT"); + case Subtypes::DescriptorRegion: return UString("Descriptor"); + case Subtypes::BiosRegion: return UString("BIOS"); + case Subtypes::MeRegion: return UString("ME"); + case Subtypes::GbeRegion: return UString("GbE"); + case Subtypes::PdrRegion: return UString("PDR"); + case Subtypes::DevExp1Region: return UString("DevExp1"); + case Subtypes::Bios2Region: return UString("BIOS2"); + case Subtypes::MicrocodeRegion: return UString("Microcode"); + case Subtypes::EcRegion: return UString("EC"); + case Subtypes::DevExp2Region: return UString("DevExp2"); + case Subtypes::IeRegion: return UString("IE"); + case Subtypes::Tgbe1Region: return UString("10GbE1"); + case Subtypes::Tgbe2Region: return UString("10GbE2"); + case Subtypes::Reserved1Region: return UString("Reserved1"); + case Subtypes::Reserved2Region: return UString("Reserved2"); + case Subtypes::PttRegion: return UString("PTT"); }; - + return UString("Unknown"); } UString itemTypeToUString(const UINT8 type) { switch (type) { - case Types::Root: return UString("Root"); - case Types::Image: return UString("Image"); - case Types::Capsule: return UString("Capsule"); - case Types::Region: return UString("Region"); - case Types::Volume: return UString("Volume"); - case Types::Padding: return UString("Padding"); - case Types::File: return UString("File"); - case Types::Section: return UString("Section"); - case Types::FreeSpace: return UString("Free space"); - case Types::VssStore: return UString("VSS store"); - case Types::Vss2Store: return UString("VSS2 store"); - case Types::FtwStore: return UString("FTW store"); - case Types::FdcStore: return UString("FDC store"); - case Types::FsysStore: return UString("Fsys store"); - case Types::EvsaStore: return UString("EVSA store"); - case Types::CmdbStore: return UString("CMDB store"); - case Types::FlashMapStore: return UString("FlashMap store"); - case Types::NvarEntry: return UString("NVAR entry"); - case Types::VssEntry: return UString("VSS entry"); - case Types::FsysEntry: return UString("Fsys entry"); - case Types::EvsaEntry: return UString("EVSA entry"); - case Types::FlashMapEntry: return UString("FlashMap entry"); - case Types::Microcode: return UString("Microcode"); - case Types::SlicData: return UString("SLIC data"); - // ME-specific - case Types::FptStore: return UString("FPT store"); - case Types::FptEntry: return UString("FPT entry"); - case Types::IfwiHeader: return UString("IFWI header"); - case Types::IfwiPartition: return UString("IFWI partition"); - case Types::FptPartition: return UString("FPT partition"); - case Types::BpdtStore: return UString("BPDT store"); - case Types::BpdtEntry: return UString("BPDT entry"); - case Types::BpdtPartition: return UString("BPDT partition"); - case Types::CpdStore: return UString("CPD store"); - case Types::CpdEntry: return UString("CPD entry"); - case Types::CpdPartition: return UString("CPD partition"); - case Types::CpdExtension: return UString("CPD extension"); - case Types::CpdSpiEntry: return UString("CPD SPI entry"); + case Types::Root: return UString("Root"); + case Types::Image: return UString("Image"); + case Types::Capsule: return UString("Capsule"); + case Types::Region: return UString("Region"); + case Types::Volume: return UString("Volume"); + case Types::Padding: return UString("Padding"); + case Types::File: return UString("File"); + case Types::Section: return UString("Section"); + case Types::FreeSpace: return UString("Free space"); + case Types::VssStore: return UString("VSS store"); + case Types::Vss2Store: return UString("VSS2 store"); + case Types::FtwStore: return UString("FTW store"); + case Types::FdcStore: return UString("FDC store"); + case Types::FsysStore: return UString("Fsys store"); + case Types::EvsaStore: return UString("EVSA store"); + case Types::CmdbStore: return UString("CMDB store"); + case Types::FlashMapStore: return UString("FlashMap store"); + case Types::NvarEntry: return UString("NVAR entry"); + case Types::VssEntry: return UString("VSS entry"); + case Types::FsysEntry: return UString("Fsys entry"); + case Types::EvsaEntry: return UString("EVSA entry"); + case Types::FlashMapEntry: return UString("FlashMap entry"); + case Types::Microcode: return UString("Microcode"); + case Types::SlicData: return UString("SLIC data"); + // ME-specific + case Types::FptStore: return UString("FPT store"); + case Types::FptEntry: return UString("FPT entry"); + case Types::IfwiHeader: return UString("IFWI header"); + case Types::IfwiPartition: return UString("IFWI partition"); + case Types::FptPartition: return UString("FPT partition"); + case Types::BpdtStore: return UString("BPDT store"); + case Types::BpdtEntry: return UString("BPDT entry"); + case Types::BpdtPartition: return UString("BPDT partition"); + case Types::CpdStore: return UString("CPD store"); + case Types::CpdEntry: return UString("CPD entry"); + case Types::CpdPartition: return UString("CPD partition"); + case Types::CpdExtension: return UString("CPD extension"); + case Types::CpdSpiEntry: return UString("CPD SPI entry"); } - + return UString("Unknown"); } UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype) { switch (type) { - case Types::Image: - if (subtype == Subtypes::IntelImage) return UString("Intel"); - if (subtype == Subtypes::UefiImage) return UString("UEFI"); - break; - case Types::Padding: - if (subtype == Subtypes::ZeroPadding) return UString("Empty (0x00)"); - if (subtype == Subtypes::OnePadding) return UString("Empty (0xFF)"); - if (subtype == Subtypes::DataPadding) return UString("Non-empty"); - break; - case Types::Volume: - if (subtype == Subtypes::UnknownVolume) return UString("Unknown"); - if (subtype == Subtypes::Ffs2Volume) return UString("FFSv2"); - if (subtype == Subtypes::Ffs3Volume) return UString("FFSv3"); - if (subtype == Subtypes::NvramVolume) return UString("NVRAM"); - if (subtype == Subtypes::MicrocodeVolume) return UString("Microcode"); - break; - case Types::Capsule: - if (subtype == Subtypes::AptioSignedCapsule) return UString("Aptio signed"); - if (subtype == Subtypes::AptioUnsignedCapsule) return UString("Aptio unsigned"); - if (subtype == Subtypes::UefiCapsule) return UString("UEFI 2.0"); - if (subtype == Subtypes::ToshibaCapsule) return UString("Toshiba"); - break; - case Types::Region: return regionTypeToUString(subtype); - case Types::File: return fileTypeToUString(subtype); - case Types::Section: return sectionTypeToUString(subtype); - case Types::NvarEntry: - if (subtype == Subtypes::InvalidNvarEntry) return UString("Invalid"); - if (subtype == Subtypes::InvalidLinkNvarEntry) return UString("Invalid link"); - if (subtype == Subtypes::LinkNvarEntry) return UString("Link"); - if (subtype == Subtypes::DataNvarEntry) return UString("Data"); - if (subtype == Subtypes::FullNvarEntry) return UString("Full"); - break; - case Types::VssEntry: - if (subtype == Subtypes::InvalidVssEntry) return UString("Invalid"); - if (subtype == Subtypes::StandardVssEntry) return UString("Standard"); - if (subtype == Subtypes::AppleVssEntry) return UString("Apple"); - if (subtype == Subtypes::AuthVssEntry) return UString("Auth"); - if (subtype == Subtypes::IntelVssEntry) return UString("Intel"); - break; - case Types::FsysEntry: - if (subtype == Subtypes::InvalidFsysEntry) return UString("Invalid"); - if (subtype == Subtypes::NormalFsysEntry) return UString("Normal"); - break; - case Types::EvsaEntry: - if (subtype == Subtypes::InvalidEvsaEntry) return UString("Invalid"); - if (subtype == Subtypes::UnknownEvsaEntry) return UString("Unknown"); - if (subtype == Subtypes::GuidEvsaEntry) return UString("GUID"); - if (subtype == Subtypes::NameEvsaEntry) return UString("Name"); - if (subtype == Subtypes::DataEvsaEntry) return UString("Data"); - break; - case Types::FlashMapEntry: - if (subtype == Subtypes::VolumeFlashMapEntry) return UString("Volume"); - if (subtype == Subtypes::DataFlashMapEntry) return UString("Data"); - break; - case Types::Microcode: - if (subtype == Subtypes::IntelMicrocode) return UString("Intel"); - if (subtype == Subtypes::AmdMicrocode) return UString("AMD"); - break; - // ME-specific - case Types::FptEntry: - if (subtype == Subtypes::ValidFptEntry) return UString("Valid"); - if (subtype == Subtypes::InvalidFptEntry) return UString("Invalid"); - break; - case Types::FptPartition: - if (subtype == Subtypes::CodeFptPartition) return UString("Code"); - if (subtype == Subtypes::DataFptPartition) return UString("Data"); - if (subtype == Subtypes::GlutFptPartition) return UString("GLUT"); - break; - case Types::IfwiPartition: - if (subtype == Subtypes::BootIfwiPartition) return UString("Boot"); - if (subtype == Subtypes::DataIfwiPartition) return UString("Data"); - break; - case Types::CpdPartition: - if (subtype == Subtypes::ManifestCpdPartition) return UString("Manifest"); - if (subtype == Subtypes::MetadataCpdPartition) return UString("Metadata"); - if (subtype == Subtypes::KeyCpdPartition) return UString("Key"); - if (subtype == Subtypes::CodeCpdPartition) return UString("Code"); - break; + case Types::Image: + if (subtype == Subtypes::IntelImage) return UString("Intel"); + if (subtype == Subtypes::UefiImage) return UString("UEFI"); + break; + case Types::Padding: + if (subtype == Subtypes::ZeroPadding) return UString("Empty (0x00)"); + if (subtype == Subtypes::OnePadding) return UString("Empty (0xFF)"); + if (subtype == Subtypes::DataPadding) return UString("Non-empty"); + break; + case Types::Volume: + if (subtype == Subtypes::UnknownVolume) return UString("Unknown"); + if (subtype == Subtypes::Ffs2Volume) return UString("FFSv2"); + if (subtype == Subtypes::Ffs3Volume) return UString("FFSv3"); + if (subtype == Subtypes::NvramVolume) return UString("NVRAM"); + if (subtype == Subtypes::MicrocodeVolume) return UString("Microcode"); + break; + case Types::Capsule: + if (subtype == Subtypes::AptioSignedCapsule) return UString("Aptio signed"); + if (subtype == Subtypes::AptioUnsignedCapsule) return UString("Aptio unsigned"); + if (subtype == Subtypes::UefiCapsule) return UString("UEFI 2.0"); + if (subtype == Subtypes::ToshibaCapsule) return UString("Toshiba"); + break; + case Types::Region: return regionTypeToUString(subtype); + case Types::File: return fileTypeToUString(subtype); + case Types::Section: return sectionTypeToUString(subtype); + case Types::NvarEntry: + if (subtype == Subtypes::InvalidNvarEntry) return UString("Invalid"); + if (subtype == Subtypes::InvalidLinkNvarEntry) return UString("Invalid link"); + if (subtype == Subtypes::LinkNvarEntry) return UString("Link"); + if (subtype == Subtypes::DataNvarEntry) return UString("Data"); + if (subtype == Subtypes::FullNvarEntry) return UString("Full"); + break; + case Types::VssEntry: + if (subtype == Subtypes::InvalidVssEntry) return UString("Invalid"); + if (subtype == Subtypes::StandardVssEntry) return UString("Standard"); + if (subtype == Subtypes::AppleVssEntry) return UString("Apple"); + if (subtype == Subtypes::AuthVssEntry) return UString("Auth"); + if (subtype == Subtypes::IntelVssEntry) return UString("Intel"); + break; + case Types::FsysEntry: + if (subtype == Subtypes::InvalidFsysEntry) return UString("Invalid"); + if (subtype == Subtypes::NormalFsysEntry) return UString("Normal"); + break; + case Types::EvsaEntry: + if (subtype == Subtypes::InvalidEvsaEntry) return UString("Invalid"); + if (subtype == Subtypes::UnknownEvsaEntry) return UString("Unknown"); + if (subtype == Subtypes::GuidEvsaEntry) return UString("GUID"); + if (subtype == Subtypes::NameEvsaEntry) return UString("Name"); + if (subtype == Subtypes::DataEvsaEntry) return UString("Data"); + break; + case Types::FlashMapEntry: + if (subtype == Subtypes::VolumeFlashMapEntry) return UString("Volume"); + if (subtype == Subtypes::DataFlashMapEntry) return UString("Data"); + break; + case Types::Microcode: + if (subtype == Subtypes::IntelMicrocode) return UString("Intel"); + if (subtype == Subtypes::AmdMicrocode) return UString("AMD"); + break; + // ME-specific + case Types::FptEntry: + if (subtype == Subtypes::ValidFptEntry) return UString("Valid"); + if (subtype == Subtypes::InvalidFptEntry) return UString("Invalid"); + break; + case Types::FptPartition: + if (subtype == Subtypes::CodeFptPartition) return UString("Code"); + if (subtype == Subtypes::DataFptPartition) return UString("Data"); + if (subtype == Subtypes::GlutFptPartition) return UString("GLUT"); + break; + case Types::IfwiPartition: + if (subtype == Subtypes::BootIfwiPartition) return UString("Boot"); + if (subtype == Subtypes::DataIfwiPartition) return UString("Data"); + break; + case Types::CpdPartition: + if (subtype == Subtypes::ManifestCpdPartition) return UString("Manifest"); + if (subtype == Subtypes::MetadataCpdPartition) return UString("Metadata"); + if (subtype == Subtypes::KeyCpdPartition) return UString("Key"); + if (subtype == Subtypes::CodeCpdPartition) return UString("Code"); + break; } - + return UString(); } UString compressionTypeToUString(const UINT8 algorithm) { switch (algorithm) { - case COMPRESSION_ALGORITHM_NONE: return UString("None"); - case COMPRESSION_ALGORITHM_EFI11: return UString("EFI 1.1"); - case COMPRESSION_ALGORITHM_TIANO: return UString("Tiano"); - case COMPRESSION_ALGORITHM_UNDECIDED: return UString("Undecided Tiano/EFI 1.1"); - case COMPRESSION_ALGORITHM_LZMA: return UString("LZMA"); - case COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY: return UString("Intel legacy LZMA"); + case COMPRESSION_ALGORITHM_NONE: return UString("None"); + case COMPRESSION_ALGORITHM_EFI11: return UString("EFI 1.1"); + case COMPRESSION_ALGORITHM_TIANO: return UString("Tiano"); + case COMPRESSION_ALGORITHM_UNDECIDED: return UString("Undecided Tiano/EFI 1.1"); + case COMPRESSION_ALGORITHM_LZMA: return UString("LZMA"); + case COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY: return UString("Intel legacy LZMA"); } - + return UString("Unknown"); } UString actionTypeToUString(const UINT8 action) { switch (action) { - case Actions::NoAction: return UString(); - case Actions::Create: return UString("Create"); - case Actions::Insert: return UString("Insert"); - case Actions::Replace: return UString("Replace"); - case Actions::Remove: return UString("Remove"); - case Actions::Rebuild: return UString("Rebuild"); - case Actions::Rebase: return UString("Rebase"); + case Actions::NoAction: return UString(); + case Actions::Create: return UString("Create"); + case Actions::Insert: return UString("Insert"); + case Actions::Replace: return UString("Replace"); + case Actions::Remove: return UString("Remove"); + case Actions::Rebuild: return UString("Rebuild"); + case Actions::Rebase: return UString("Rebase"); } - + return UString("Unknown"); } UString fitEntryTypeToUString(const UINT8 type) { switch (type & 0x7F) { - case FIT_TYPE_HEADER: return UString("FIT Header"); - case FIT_TYPE_MICROCODE: return UString("Microcode"); - case FIT_TYPE_BIOS_AC_MODULE: return UString("BIOS ACM"); - case FIT_TYPE_BIOS_INIT_MODULE: return UString("BIOS Init"); - case FIT_TYPE_TPM_POLICY: return UString("TPM Policy"); - case FIT_TYPE_BIOS_POLICY_DATA: return UString("BIOS Policy Data"); - case FIT_TYPE_TXT_CONF_POLICY: return UString("TXT Configuration Policy"); - case FIT_TYPE_AC_KEY_MANIFEST: return UString("BootGuard Key Manifest"); - case FIT_TYPE_AC_BOOT_POLICY: return UString("BootGuard Boot Policy"); - case FIT_TYPE_EMPTY: return UString("Empty"); + case FIT_TYPE_HEADER: return UString("FIT Header"); + case FIT_TYPE_MICROCODE: return UString("Microcode"); + case FIT_TYPE_BIOS_AC_MODULE: return UString("BIOS ACM"); + case FIT_TYPE_BIOS_INIT_MODULE: return UString("BIOS Init"); + case FIT_TYPE_TPM_POLICY: return UString("TPM Policy"); + case FIT_TYPE_BIOS_POLICY_DATA: return UString("BIOS Policy Data"); + case FIT_TYPE_TXT_CONF_POLICY: return UString("TXT Configuration Policy"); + case FIT_TYPE_AC_KEY_MANIFEST: return UString("BootGuard Key Manifest"); + case FIT_TYPE_AC_BOOT_POLICY: return UString("BootGuard Boot Policy"); + case FIT_TYPE_EMPTY: return UString("Empty"); } - + return UString("Unknown"); -} \ No newline at end of file +} diff --git a/common/uinttypes.h b/common/uinttypes.h index e104dc0..10b0a32 100644 --- a/common/uinttypes.h +++ b/common/uinttypes.h @@ -16,7 +16,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // A workaround for compilers not supporting c++11 and c11 // for using PRIX64. #define __STDC_FORMAT_MACROS - #include #if defined(__clang__) || defined(__GNUC__) diff --git a/common/ustring.cpp b/common/ustring.cpp index a6efd7f..9166fcf 100644 --- a/common/ustring.cpp +++ b/common/ustring.cpp @@ -1,14 +1,14 @@ /* ustring.cpp - -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 -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -*/ + + 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 + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + */ #include "ustring.h" #include @@ -19,9 +19,9 @@ UString usprintf(const char* fmt, ...) UString msg; va_list vl; va_start(vl, fmt); - + msg = msg.vasprintf(fmt, vl); - + va_end(vl); return msg; }; @@ -37,16 +37,16 @@ UString urepeated(char c, int len) #else #ifdef BSTRLIB_NOVSNP /* This is just a hack. If you are using a system without a vsnprintf, it is -not recommended that bformat be used at all. */ + not recommended that bformat be used at all. */ #define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;} #define START_VSNBUFF (256) #else #if defined (__GNUC__) && !defined (__PPC__) && !defined(__WIN32__) /* Something is making gcc complain about this prototype not being here, so -I've just gone ahead and put it in. */ + I've just gone ahead and put it in. */ extern "C" { - extern int vsnprintf(char *buf, size_t count, const char *format, va_list arg); +extern int vsnprintf(char *buf, size_t count, const char *format, va_list arg); } #endif @@ -64,12 +64,12 @@ UString usprintf(const char* fmt, ...) bstring b; va_list arglist; int r, n; - + if (fmt == NULL) { msg = ""; } else { - + if ((b = bfromcstr("")) == NULL) { msg = ""; } @@ -80,14 +80,14 @@ UString usprintf(const char* fmt, ...) b = bformat(""); break; } - + va_start(arglist, fmt); exvsnprintf(r, (char *)b->data, n + 1, fmt, arglist); va_end(arglist); - + b->data[n] = '\0'; b->slen = (int)(strlen)((char *)b->data); - + if (b->slen < n) break; if (r > n) n = r; else n += n; } @@ -95,7 +95,7 @@ UString usprintf(const char* fmt, ...) bdestroy(b); } } - + return msg; } diff --git a/common/utility.cpp b/common/utility.cpp index a054879..b3216a9 100755 --- a/common/utility.cpp +++ b/common/utility.cpp @@ -1,15 +1,15 @@ /* utility.cpp - -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 -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -*/ + + 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 + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + */ #include #include @@ -40,7 +40,7 @@ UString visibleAsciiOrHex(UINT8* bytes, UINT32 length) break; } } - + if (ascii) { // No need to continue iterating over every symbol, we did it already break; @@ -49,7 +49,7 @@ UString visibleAsciiOrHex(UINT8* bytes, UINT32 length) else if (bytes[i] < '\x20' || bytes[i] > '\x7E') { // Explicit ascii codes to avoid locale dependency ascii = false; } - + if (ascii) { asciiString += usprintf("%c", bytes[i]); } @@ -68,48 +68,48 @@ UString uniqueItemName(const UModelIndex & index) // Sanity check if (!index.isValid()) return UString("Invalid_index"); - + // Get model from index const TreeModel* model = (const TreeModel*)index.model(); // Construct the name UString itemName = model->name(index); UString itemText = model->text(index); - + // Default name UString name = itemName; switch (model->type(index)) { - case Types::NvarEntry: - case Types::VssEntry: - case Types::FsysEntry: - case Types::EvsaEntry: - case Types::FlashMapEntry: - case Types::File: - name = itemText.isEmpty() ? itemName : itemName + '_' + itemText; - break; - case Types::Section: { - // Get parent file name - UModelIndex fileIndex = model->findParentOfType(index, Types::File); - UString fileText = model->text(fileIndex); - name = fileText.isEmpty() ? model->name(fileIndex) : model->name(fileIndex) + '_' + fileText; - - // Special case of GUIDed sections - if (model->subtype(index) == EFI_SECTION_GUID_DEFINED || model->subtype(index) == EFI_SECTION_FREEFORM_SUBTYPE_GUID) { - name = model->name(index) +'_' + name; - } - } break; + case Types::NvarEntry: + case Types::VssEntry: + case Types::FsysEntry: + case Types::EvsaEntry: + case Types::FlashMapEntry: + case Types::File: + name = itemText.isEmpty() ? itemName : itemName + '_' + itemText; + break; + case Types::Section: { + // Get parent file name + UModelIndex fileIndex = model->findParentOfType(index, Types::File); + UString fileText = model->text(fileIndex); + name = fileText.isEmpty() ? model->name(fileIndex) : model->name(fileIndex) + '_' + fileText; + + // Special case of GUIDed sections + if (model->subtype(index) == EFI_SECTION_GUID_DEFINED || model->subtype(index) == EFI_SECTION_FREEFORM_SUBTYPE_GUID) { + name = model->name(index) +'_' + name; + } + } break; } - + // Populate subtypeString UString subtypeString = itemSubtypeToUString(model->type(index), model->subtype(index)); - + // Create final name name = itemTypeToUString(model->type(index)) - + (subtypeString.length() ? ('_' + subtypeString) : UString()) - + '_' + name; - + + (subtypeString.length() ? ('_' + subtypeString) : UString()) + + '_' + name; + fixFileName(name, true); - + return name; } @@ -127,10 +127,10 @@ void fixFileName(UString &name, bool replaceSpaces) name[i] < (char)0x20 || // ASCII control characters, banned in Windows, hard to work with in *nix name[i] > (char)0x7f || // high ASCII characters (replaceSpaces && name[i] == ' ') // Provides better readability - ) { - name[i] = '_'; - continue; - } + ) { + name[i] = '_'; + continue; + } for (size_t j = 0; j < sizeof(table); j++) { if (name[i] == table[j]) { name[i] = '_'; @@ -147,57 +147,57 @@ void fixFileName(UString &name, bool replaceSpaces) UString errorCodeToUString(USTATUS errorCode) { switch (errorCode) { - case U_SUCCESS: return UString("Success"); - case U_NOT_IMPLEMENTED: return UString("Not implemented"); - case U_INVALID_PARAMETER: return UString("Function called with invalid parameter"); - case U_BUFFER_TOO_SMALL: return UString("Buffer too small"); - case U_OUT_OF_RESOURCES: return UString("Out of resources"); - case U_OUT_OF_MEMORY: return UString("Out of memory"); - case U_FILE_OPEN: return UString("File can't be opened"); - case U_FILE_READ: return UString("File can't be read"); - case U_FILE_WRITE: return UString("File can't be written"); - case U_ITEM_NOT_FOUND: return UString("Item not found"); - case U_UNKNOWN_ITEM_TYPE: return UString("Unknown item type"); - case U_INVALID_FLASH_DESCRIPTOR: return UString("Invalid flash descriptor"); - case U_INVALID_REGION: return UString("Invalid region"); - case U_EMPTY_REGION: return UString("Empty region"); - case U_BIOS_REGION_NOT_FOUND: return UString("BIOS region not found"); - case U_VOLUMES_NOT_FOUND: return UString("UEFI volumes not found"); - case U_INVALID_VOLUME: return UString("Invalid UEFI volume"); - case U_VOLUME_REVISION_NOT_SUPPORTED: return UString("Volume revision not supported"); - //case U_VOLUME_GROW_FAILED: return UString("Volume grow failed"); - case U_UNKNOWN_FFS: return UString("Unknown file system"); - case U_INVALID_FILE: return UString("Invalid file"); - case U_INVALID_SECTION: return UString("Invalid section"); - case U_UNKNOWN_SECTION: return UString("Unknown section"); - case U_STANDARD_COMPRESSION_FAILED: return UString("Standard compression failed"); - case U_CUSTOMIZED_COMPRESSION_FAILED: return UString("Customized compression failed"); - case U_STANDARD_DECOMPRESSION_FAILED: return UString("Standard decompression failed"); - case U_CUSTOMIZED_DECOMPRESSION_FAILED: return UString("Customized decompression failed"); - case U_UNKNOWN_COMPRESSION_TYPE: return UString("Unknown compression type"); - case U_UNKNOWN_EXTRACT_MODE: return UString("Unknown extract mode"); - case U_UNKNOWN_REPLACE_MODE: return UString("Unknown replace mode"); - //case U_UNKNOWN_INSERT_MODE: return UString("Unknown insert mode"); - case U_UNKNOWN_IMAGE_TYPE: return UString("Unknown executable image type"); - case U_UNKNOWN_PE_OPTIONAL_HEADER_TYPE: return UString("Unknown PE optional header type"); - case U_UNKNOWN_RELOCATION_TYPE: return UString("Unknown relocation type"); - //case U_GENERIC_CALL_NOT_SUPPORTED: return UString("Generic call not supported"); - //case U_VOLUME_BASE_NOT_FOUND: return UString("Volume base address not found"); - //case U_PEI_CORE_ENTRY_POINT_NOT_FOUND: return UString("PEI core entry point not found"); - case U_COMPLEX_BLOCK_MAP: return UString("Block map structure too complex for correct analysis"); - case U_DIR_ALREADY_EXIST: return UString("Directory already exists"); - case U_DIR_CREATE: return UString("Directory can't be created"); - case U_DIR_CHANGE: return UString("Change directory failed"); - //case U_UNKNOWN_PATCH_TYPE: return UString("Unknown patch type"); - //case U_PATCH_OFFSET_OUT_OF_BOUNDS: return UString("Patch offset out of bounds"); - //case U_INVALID_SYMBOL: return UString("Invalid symbol"); - //case U_NOTHING_TO_PATCH: return UString("Nothing to patch"); - case U_DEPEX_PARSE_FAILED: return UString("Dependency expression parsing failed"); - case U_TRUNCATED_IMAGE: return UString("Image is truncated"); - case U_INVALID_CAPSULE: return UString("Invalid capsule"); - case U_STORES_NOT_FOUND: return UString("Stores not found"); - case U_INVALID_STORE_SIZE: return UString("Invalid store size"); - default: return usprintf("Unknown error %02lX", errorCode); + case U_SUCCESS: return UString("Success"); + case U_NOT_IMPLEMENTED: return UString("Not implemented"); + case U_INVALID_PARAMETER: return UString("Function called with invalid parameter"); + case U_BUFFER_TOO_SMALL: return UString("Buffer too small"); + case U_OUT_OF_RESOURCES: return UString("Out of resources"); + case U_OUT_OF_MEMORY: return UString("Out of memory"); + case U_FILE_OPEN: return UString("File can't be opened"); + case U_FILE_READ: return UString("File can't be read"); + case U_FILE_WRITE: return UString("File can't be written"); + case U_ITEM_NOT_FOUND: return UString("Item not found"); + case U_UNKNOWN_ITEM_TYPE: return UString("Unknown item type"); + case U_INVALID_FLASH_DESCRIPTOR: return UString("Invalid flash descriptor"); + case U_INVALID_REGION: return UString("Invalid region"); + case U_EMPTY_REGION: return UString("Empty region"); + case U_BIOS_REGION_NOT_FOUND: return UString("BIOS region not found"); + case U_VOLUMES_NOT_FOUND: return UString("UEFI volumes not found"); + case U_INVALID_VOLUME: return UString("Invalid UEFI volume"); + case U_VOLUME_REVISION_NOT_SUPPORTED: return UString("Volume revision not supported"); + //case U_VOLUME_GROW_FAILED: return UString("Volume grow failed"); + case U_UNKNOWN_FFS: return UString("Unknown file system"); + case U_INVALID_FILE: return UString("Invalid file"); + case U_INVALID_SECTION: return UString("Invalid section"); + case U_UNKNOWN_SECTION: return UString("Unknown section"); + case U_STANDARD_COMPRESSION_FAILED: return UString("Standard compression failed"); + case U_CUSTOMIZED_COMPRESSION_FAILED: return UString("Customized compression failed"); + case U_STANDARD_DECOMPRESSION_FAILED: return UString("Standard decompression failed"); + case U_CUSTOMIZED_DECOMPRESSION_FAILED: return UString("Customized decompression failed"); + case U_UNKNOWN_COMPRESSION_TYPE: return UString("Unknown compression type"); + case U_UNKNOWN_EXTRACT_MODE: return UString("Unknown extract mode"); + case U_UNKNOWN_REPLACE_MODE: return UString("Unknown replace mode"); + //case U_UNKNOWN_INSERT_MODE: return UString("Unknown insert mode"); + case U_UNKNOWN_IMAGE_TYPE: return UString("Unknown executable image type"); + case U_UNKNOWN_PE_OPTIONAL_HEADER_TYPE: return UString("Unknown PE optional header type"); + case U_UNKNOWN_RELOCATION_TYPE: return UString("Unknown relocation type"); + //case U_GENERIC_CALL_NOT_SUPPORTED: return UString("Generic call not supported"); + //case U_VOLUME_BASE_NOT_FOUND: return UString("Volume base address not found"); + //case U_PEI_CORE_ENTRY_POINT_NOT_FOUND: return UString("PEI core entry point not found"); + case U_COMPLEX_BLOCK_MAP: return UString("Block map structure too complex for correct analysis"); + case U_DIR_ALREADY_EXIST: return UString("Directory already exists"); + case U_DIR_CREATE: return UString("Directory can't be created"); + case U_DIR_CHANGE: return UString("Change directory failed"); + //case U_UNKNOWN_PATCH_TYPE: return UString("Unknown patch type"); + //case U_PATCH_OFFSET_OUT_OF_BOUNDS: return UString("Patch offset out of bounds"); + //case U_INVALID_SYMBOL: return UString("Invalid symbol"); + //case U_NOTHING_TO_PATCH: return UString("Nothing to patch"); + case U_DEPEX_PARSE_FAILED: return UString("Dependency expression parsing failed"); + case U_TRUNCATED_IMAGE: return UString("Image is truncated"); + case U_INVALID_CAPSULE: return UString("Invalid capsule"); + case U_STORES_NOT_FOUND: return UString("Stores not found"); + case U_INVALID_STORE_SIZE: return UString("Invalid store size"); + default: return usprintf("Unknown error %02lX", errorCode); } } @@ -212,169 +212,169 @@ USTATUS decompress(const UByteArray & compressedData, const UINT8 compressionTyp UINT8* scratch; UINT32 scratchSize = 0; const EFI_TIANO_HEADER* header; - + // For all but LZMA dictionary size is 0 dictionarySize = 0; - + switch (compressionType) { - case EFI_NOT_COMPRESSED: { - decompressedData = compressedData; - algorithm = COMPRESSION_ALGORITHM_NONE; - return U_SUCCESS; + case EFI_NOT_COMPRESSED: { + decompressedData = compressedData; + algorithm = COMPRESSION_ALGORITHM_NONE; + return U_SUCCESS; } - case EFI_STANDARD_COMPRESSION: { - // Set default algorithm to unknown - algorithm = COMPRESSION_ALGORITHM_UNKNOWN; - - // Get buffer sizes - data = (UINT8*)compressedData.data(); - dataSize = (UINT32)compressedData.size(); - - // Check header to be valid - header = (const EFI_TIANO_HEADER*)data; - if (header->CompSize + sizeof(EFI_TIANO_HEADER) != dataSize) - return U_STANDARD_DECOMPRESSION_FAILED; - - // Get info function is the same for both algorithms - if (U_SUCCESS != EfiTianoGetInfo(data, dataSize, &decompressedSize, &scratchSize)) - return U_STANDARD_DECOMPRESSION_FAILED; - - // Allocate memory - decompressed = (UINT8*)malloc(decompressedSize); - efiDecompressed = (UINT8*)malloc(decompressedSize); - scratch = (UINT8*)malloc(scratchSize); - if (!decompressed || !efiDecompressed || !scratch) { + case EFI_STANDARD_COMPRESSION: { + // Set default algorithm to unknown + algorithm = COMPRESSION_ALGORITHM_UNKNOWN; + + // Get buffer sizes + data = (UINT8*)compressedData.data(); + dataSize = (UINT32)compressedData.size(); + + // Check header to be valid + header = (const EFI_TIANO_HEADER*)data; + if (header->CompSize + sizeof(EFI_TIANO_HEADER) != dataSize) + return U_STANDARD_DECOMPRESSION_FAILED; + + // Get info function is the same for both algorithms + if (U_SUCCESS != EfiTianoGetInfo(data, dataSize, &decompressedSize, &scratchSize)) + return U_STANDARD_DECOMPRESSION_FAILED; + + // Allocate memory + decompressed = (UINT8*)malloc(decompressedSize); + efiDecompressed = (UINT8*)malloc(decompressedSize); + scratch = (UINT8*)malloc(scratchSize); + if (!decompressed || !efiDecompressed || !scratch) { + free(decompressed); + free(efiDecompressed); + free(scratch); + return U_STANDARD_DECOMPRESSION_FAILED; + } + + // Decompress section data using both algorithms + USTATUS result = U_SUCCESS; + // Try Tiano + USTATUS TianoResult = TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize); + // Try EFI 1.1 + USTATUS EfiResult = EfiDecompress(data, dataSize, efiDecompressed, decompressedSize, scratch, scratchSize); + + if (decompressedSize > INT32_MAX) { + result = U_STANDARD_DECOMPRESSION_FAILED; + } + else if (EfiResult == U_SUCCESS && TianoResult == U_SUCCESS) { // Both decompressions are OK + algorithm = COMPRESSION_ALGORITHM_UNDECIDED; + decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); + efiDecompressedData = UByteArray((const char*)efiDecompressed, (int)decompressedSize); + } + else if (TianoResult == U_SUCCESS) { // Only Tiano is OK + algorithm = COMPRESSION_ALGORITHM_TIANO; + decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); + } + else if (EfiResult == U_SUCCESS) { // Only EFI 1.1 is OK + algorithm = COMPRESSION_ALGORITHM_EFI11; + decompressedData = UByteArray((const char*)efiDecompressed, (int)decompressedSize); + } + else { // Both decompressions failed + result = U_STANDARD_DECOMPRESSION_FAILED; + } + free(decompressed); free(efiDecompressed); free(scratch); - return U_STANDARD_DECOMPRESSION_FAILED; + return result; } - - // Decompress section data using both algorithms - USTATUS result = U_SUCCESS; - // Try Tiano - USTATUS TianoResult = TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize); - // Try EFI 1.1 - USTATUS EfiResult = EfiDecompress(data, dataSize, efiDecompressed, decompressedSize, scratch, scratchSize); - - if (decompressedSize > INT32_MAX) { - result = U_STANDARD_DECOMPRESSION_FAILED; - } - else if (EfiResult == U_SUCCESS && TianoResult == U_SUCCESS) { // Both decompressions are OK - algorithm = COMPRESSION_ALGORITHM_UNDECIDED; + case EFI_CUSTOMIZED_COMPRESSION: { + // Set default algorithm to unknown + algorithm = COMPRESSION_ALGORITHM_UNKNOWN; + + // Get buffer sizes + data = (const UINT8*)compressedData.constData(); + dataSize = (UINT32)compressedData.size(); + + // Get info as normal LZMA section + if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) { + // Get info as Intel legacy LZMA section + data += sizeof(UINT32); + if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) { + return U_CUSTOMIZED_DECOMPRESSION_FAILED; + } + else { + algorithm = COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY; + } + } + else { + algorithm = COMPRESSION_ALGORITHM_LZMA; + } + + // Allocate memory + decompressed = (UINT8*)malloc(decompressedSize); + if (!decompressed) { + return U_OUT_OF_MEMORY; + } + + // Decompress section data + if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { + free(decompressed); + return U_CUSTOMIZED_DECOMPRESSION_FAILED; + } + + if (decompressedSize > INT32_MAX) { + free(decompressed); + return U_CUSTOMIZED_DECOMPRESSION_FAILED; + } + + dictionarySize = readUnaligned((UINT32*)(data + 1)); // LZMA dictionary size is stored in bytes 1-4 of LZMA properties header decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); - efiDecompressedData = UByteArray((const char*)efiDecompressed, (int)decompressedSize); + free(decompressed); + return U_SUCCESS; } - else if (TianoResult == U_SUCCESS) { // Only Tiano is OK - algorithm = COMPRESSION_ALGORITHM_TIANO; - decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); - } - else if (EfiResult == U_SUCCESS) { // Only EFI 1.1 is OK - algorithm = COMPRESSION_ALGORITHM_EFI11; - decompressedData = UByteArray((const char*)efiDecompressed, (int)decompressedSize); - } - else { // Both decompressions failed - result = U_STANDARD_DECOMPRESSION_FAILED; - } - - free(decompressed); - free(efiDecompressed); - free(scratch); - return result; - } - case EFI_CUSTOMIZED_COMPRESSION: { - // Set default algorithm to unknown - algorithm = COMPRESSION_ALGORITHM_UNKNOWN; - - // Get buffer sizes - data = (const UINT8*)compressedData.constData(); - dataSize = (UINT32)compressedData.size(); - - // Get info as normal LZMA section - if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) { - // Get info as Intel legacy LZMA section - data += sizeof(UINT32); + case EFI_CUSTOMIZED_COMPRESSION_LZMAF86: { + // Set default algorithm to unknown + algorithm = COMPRESSION_ALGORITHM_UNKNOWN; + + // Get buffer sizes + data = (const UINT8*)compressedData.constData(); + dataSize = (UINT32)compressedData.size(); + + // Get info as normal LZMA section if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) { return U_CUSTOMIZED_DECOMPRESSION_FAILED; } - else { - algorithm = COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY; + algorithm = COMPRESSION_ALGORITHM_LZMAF86; + + // Allocate memory + decompressed = (UINT8*)malloc(decompressedSize); + if (!decompressed) { + return U_OUT_OF_MEMORY; } - } - else { - algorithm = COMPRESSION_ALGORITHM_LZMA; - } - - // Allocate memory - decompressed = (UINT8*)malloc(decompressedSize); - if (!decompressed) { - return U_OUT_OF_MEMORY; - } - - // Decompress section data - if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { + + // Decompress section data + if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { + free(decompressed); + return U_CUSTOMIZED_DECOMPRESSION_FAILED; + } + + if (decompressedSize > INT32_MAX) { + free(decompressed); + return U_CUSTOMIZED_DECOMPRESSION_FAILED; + } + + // After LZMA decompression, the data need to be converted to the raw data. + UINT32 state = 0; + const UINT8 x86LookAhead = 4; + if (decompressedSize != x86LookAhead + x86_Convert(decompressed, decompressedSize, 0, &state, 0)) { + free(decompressed); + return U_CUSTOMIZED_DECOMPRESSION_FAILED; + } + + dictionarySize = readUnaligned((UINT32*)(data + 1)); // LZMA dictionary size is stored in bytes 1-4 of LZMA properties header + decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); free(decompressed); - return U_CUSTOMIZED_DECOMPRESSION_FAILED; + return U_SUCCESS; } - - if (decompressedSize > INT32_MAX) { - free(decompressed); - return U_CUSTOMIZED_DECOMPRESSION_FAILED; - } - - dictionarySize = readUnaligned((UINT32*)(data + 1)); // LZMA dictionary size is stored in bytes 1-4 of LZMA properties header - decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); - free(decompressed); - return U_SUCCESS; - } - case EFI_CUSTOMIZED_COMPRESSION_LZMAF86: { - // Set default algorithm to unknown - algorithm = COMPRESSION_ALGORITHM_UNKNOWN; - - // Get buffer sizes - data = (const UINT8*)compressedData.constData(); - dataSize = (UINT32)compressedData.size(); - - // Get info as normal LZMA section - if (U_SUCCESS != LzmaGetInfo(data, dataSize, &decompressedSize)) { - return U_CUSTOMIZED_DECOMPRESSION_FAILED; - } - algorithm = COMPRESSION_ALGORITHM_LZMAF86; - - // Allocate memory - decompressed = (UINT8*)malloc(decompressedSize); - if (!decompressed) { - return U_OUT_OF_MEMORY; - } - - // Decompress section data - if (U_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { - free(decompressed); - return U_CUSTOMIZED_DECOMPRESSION_FAILED; - } - - if (decompressedSize > INT32_MAX) { - free(decompressed); - return U_CUSTOMIZED_DECOMPRESSION_FAILED; - } - - // After LZMA decompression, the data need to be converted to the raw data. - UINT32 state = 0; - const UINT8 x86LookAhead = 4; - if (decompressedSize != x86LookAhead + x86_Convert(decompressed, decompressedSize, 0, &state, 0)) { - free(decompressed); - return U_CUSTOMIZED_DECOMPRESSION_FAILED; - } - - dictionarySize = readUnaligned((UINT32*)(data + 1)); // LZMA dictionary size is stored in bytes 1-4 of LZMA properties header - decompressedData = UByteArray((const char*)decompressed, (int)decompressedSize); - free(decompressed); - return U_SUCCESS; - } - default: { - algorithm = COMPRESSION_ALGORITHM_UNKNOWN; - return U_UNKNOWN_COMPRESSION_TYPE; + default: { + algorithm = COMPRESSION_ALGORITHM_UNKNOWN; + return U_UNKNOWN_COMPRESSION_TYPE; } } } @@ -386,12 +386,12 @@ UINT8 calculateSum8(const UINT8* buffer, UINT32 bufferSize) { if (!buffer) return 0; - + UINT8 counter = 0; - + while (bufferSize--) counter += buffer[bufferSize]; - + return counter; } @@ -400,7 +400,7 @@ UINT8 calculateChecksum8(const UINT8* buffer, UINT32 bufferSize) { if (!buffer) return 0; - + return (UINT8)(0x100U - calculateSum8(buffer, bufferSize)); } @@ -409,16 +409,16 @@ UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize) { if (!buffer) return 0; - + UINT16 counter = 0; UINT32 index = 0; - + bufferSize /= sizeof(UINT16); - + for (; index < bufferSize; index++) { counter = (UINT16)(counter + buffer[index]); } - + return (UINT16)(0x10000 - counter); } @@ -462,11 +462,11 @@ static inline int char2hex(char c) } INTN findPattern(const UINT8 *pattern, const UINT8 *patternMask, UINTN patternSize, - const UINT8 *data, UINTN dataSize, UINTN dataOff) + const UINT8 *data, UINTN dataSize, UINTN dataOff) { if (patternSize == 0 || dataSize == 0 || dataOff >= dataSize || dataSize - dataOff < patternSize) return -1; - + while (dataOff + patternSize < dataSize) { BOOLEAN matches = TRUE; for (UINTN i = 0; i < patternSize; i++) { @@ -475,78 +475,78 @@ INTN findPattern(const UINT8 *pattern, const UINT8 *patternMask, UINTN patternSi break; } } - + if (matches) return static_cast(dataOff); - + dataOff++; } - + return -1; } BOOLEAN makePattern(const CHAR8 *textPattern, std::vector &pattern, std::vector &patternMask) { UINTN len = std::strlen(textPattern); - + if (len == 0 || len % 2 != 0) return FALSE; - + len /= 2; - + pattern.resize(len); patternMask.resize(len); - + for (UINTN i = 0; i < len; i++) { int v1 = char2hex(std::toupper(textPattern[i * 2])); int v2 = char2hex(std::toupper(textPattern[i * 2 + 1])); - + if (v1 == -1 || v2 == -1) return FALSE; - + if (v1 != -2) { patternMask[i] = 0xF0; pattern[i] = static_cast(v1) << 4; } - + if (v2 != -2) { patternMask[i] |= 0x0F; pattern[i] |= static_cast(v2); } } - + return TRUE; } USTATUS gzipDecompress(const UByteArray & input, UByteArray & output) { output.clear(); - + if (input.size() == 0) return U_SUCCESS; - + z_stream stream; stream.next_in = (z_const Bytef *)input.data(); stream.avail_in = (uInt)input.size(); stream.zalloc = Z_NULL; stream.zfree = Z_NULL; stream.opaque = Z_NULL; - + // 15 for the maximum history buffer, 16 for gzip only input. int ret = inflateInit2(&stream, 15U | 16U); if (ret != Z_OK) return U_GZIP_DECOMPRESSION_FAILED; - + while (ret == Z_OK) { Bytef out[4096]; stream.next_out = out; stream.avail_out = sizeof(out); - + ret = inflate(&stream, Z_NO_FLUSH); if ((ret == Z_OK || ret == Z_STREAM_END) && stream.avail_out != sizeof(out)) output += UByteArray((char *)out, sizeof(out) - stream.avail_out); } - + inflateEnd(&stream); return ret == Z_STREAM_END ? U_SUCCESS : U_GZIP_DECOMPRESSION_FAILED; }