diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp
index 8dd751c..5fb0120 100644
--- a/UEFITool/uefitool.cpp
+++ b/UEFITool/uefitool.cpp
@@ -55,6 +55,7 @@ version(tr("0.30.0_alpha22"))
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about()));
connect(ui->actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt()));
connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(exit()));
+ connect(ui->actionGoToData, SIGNAL(triggered()), this, SLOT(goToData()));
connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(writeSettings()));
// Enable Drag-and-Drop actions
@@ -161,7 +162,7 @@ void UEFITool::populateUi(const QModelIndex ¤t)
return;
UINT8 type = model->type(current);
- //UINT8 subtype = model->subtype(current);
+ UINT8 subtype = model->subtype(current);
// Set info text
ui->infoEdit->setPlainText(model->info(current));
@@ -174,10 +175,12 @@ void UEFITool::populateUi(const QModelIndex ¤t)
ui->menuVolumeActions->setEnabled(type == Types::Volume);
ui->menuFileActions->setEnabled(type == Types::File);
ui->menuSectionActions->setEnabled(type == Types::Section);
+ ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar);
// Enable actions
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current));
-
+ ui->actionGoToData->setEnabled(type == Types::NvramVariableNvar && subtype == Subtypes::LinkNvar);
+
// Disable rebuild for now
//ui->actionRebuild->setDisabled(type == Types::Region && subtype == Subtypes::DescriptorRegion);
//ui->actionReplace->setDisabled(type == Types::Region && subtype == Subtypes::DescriptorRegion);
@@ -271,6 +274,34 @@ void UEFITool::search()
}
}
+void UEFITool::goToData()
+{
+ QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
+ if (!index.isValid() || model->type(index) != Types::NvramVariableNvar || model->subtype(index) != Subtypes::LinkNvar)
+ return;
+
+ // Get parent
+ QModelIndex parent = model->parent(index);
+
+ for (int i = index.row(); i < model->rowCount(parent); i++) {
+ PARSING_DATA pdata = parsingDataFromQModelIndex(index);
+ UINT32 lastVariableFlag = pdata.emptyByte ? 0xFFFFFF : 0;
+ if (pdata.nvram.nvar.next == lastVariableFlag) {
+ 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.child(j, 0);
+ PARSING_DATA currentPdata = parsingDataFromQModelIndex(currentIndex);
+ if (currentPdata.offset == pdata.offset + pdata.nvram.nvar.next) {
+ index = currentIndex;
+ break;
+ }
+ }
+ }
+}
+
void UEFITool::insert(const UINT8 mode)
{
/*QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
@@ -497,7 +528,10 @@ void UEFITool::extract(const UINT8 mode)
path = QFileDialog::getSaveFileName(this, tr("Save FFS file to file"), name + ".ffs", "FFS files (*.ffs *.bin);;All files (*)");
break;
case Types::Section:
- path = QFileDialog::getSaveFileName(this, tr("Save section file to file"), name + ".sct", "Section files (*.sct *.bin);;All files (*)");
+ path = QFileDialog::getSaveFileName(this, tr("Save section to file"), name + ".sct", "Section files (*.sct *.bin);;All files (*)");
+ break;
+ case Types::NvramVariableNvar:
+ path = QFileDialog::getSaveFileName(this, tr("Save NVAR variable to file"), name + ".nvar", "NVAR variable files (*.nvar *.bin);;All files (*)");
break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
@@ -531,6 +565,9 @@ void UEFITool::extract(const UINT8 mode)
path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
break;
+ case Types::NvramVariableNvar:
+ path = QFileDialog::getSaveFileName(this, tr("Save NVAR variable body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
+ break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
@@ -847,8 +884,7 @@ void UEFITool::scrollTreeView(QListWidgetItem* item)
QModelIndex index = messageItem->index();
if (index.isValid()) {
ui->structureTreeView->scrollTo(index, QAbstractItemView::PositionAtCenter);
- ui->structureTreeView->selectionModel()->clearSelection();
- ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
+ ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows | QItemSelectionModel::Clear);
}
}
@@ -893,6 +929,9 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
case Types::Section:
ui->menuSectionActions->exec(event->globalPos());
break;
+ case Types::NvramVariableNvar:
+ ui->menuVariableActions->exec(event->globalPos());
+ break;
}
}
diff --git a/UEFITool/uefitool.h b/UEFITool/uefitool.h
index 2a25997..ea505e5 100644
--- a/UEFITool/uefitool.h
+++ b/UEFITool/uefitool.h
@@ -71,6 +71,7 @@ private slots:
void saveImageFile();
void search();
+ void goToData();
void extract(const UINT8 mode);
void extractAsIs();
void extractBody();
diff --git a/UEFITool/uefitool.ui b/UEFITool/uefitool.ui
index c18b774..9dd1f31 100644
--- a/UEFITool/uefitool.ui
+++ b/UEFITool/uefitool.ui
@@ -394,6 +394,20 @@
+
@@ -401,6 +415,7 @@
+
@@ -646,6 +661,11 @@
Ctrl+Alt+E
+
+
+ Go to &data
+
+
diff --git a/common/ffsops.cpp b/common/ffsops.cpp
index b24b4b6..2d38cd5 100644
--- a/common/ffsops.cpp
+++ b/common/ffsops.cpp
@@ -56,6 +56,7 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
else
name = itemName;
} break;
+ case Types::NvramVariableNvar:
case Types::File: {
name = itemText.isEmpty() ? itemName : itemText.replace(' ', '_');
} break;
@@ -67,7 +68,6 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
// Append section subtype name
name += QChar('_') + itemName.replace(' ', '_');
} break;
-
case Types::Capsule:
case Types::Image:
case Types::Region:
diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp
index 847ee69..bf2bd40 100644
--- a/common/ffsparser.cpp
+++ b/common/ffsparser.cpp
@@ -1610,7 +1610,7 @@ STATUS FfsParser::parseFileHeader(const QByteArray & file, const UINT32 parentOf
text = QObject::tr("Volume Top File");
}
// Check if the file is NVRAM storage with NVAR format
- else if (guid == NVRAM_NVAR_FILE_GUID) {
+ else if (guid == NVRAM_NVAR_STORAGE_FILE_GUID || guid == NVRAM_NVAR_EXTERNAL_DEFAULTS_FILE_GUID) {
// Mark the file as NVAR storage
pdata.file.format = RAW_FILE_FORMAT_NVAR_STORAGE;
}
@@ -2883,7 +2883,8 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
UINT32 offset = 0;
UINT32 guidsInStorage = 0;
-
+
+ // Parse all variables
while (1) {
bool msgUnknownExtDataFormat = false;
bool msgExtHeaderTooLong = false;
@@ -2919,6 +2920,7 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
if (unparsedSize < sizeof(NVAR_VARIABLE_HEADER) ||
variableHeader->Signature != NVRAM_NVAR_VARIABLE_SIGNATURE ||
unparsedSize < variableHeader->Size) {
+
// Check if the data left is a free space or a padding
QByteArray padding = data.mid(offset, unparsedSize);
UINT8 type;
@@ -2930,6 +2932,12 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
subtype = 0;
}
else {
+ // Nothing is parsed yet, but the file is not empty
+ if (!offset) {
+ msg(QObject::tr("parseNvarStorage: file can't be parsed as NVAR variables storage"), index);
+ return ERR_INVALID_FILE;
+ }
+
// It's a padding
name = QObject::tr("Padding");
type = Types::Padding;
@@ -2962,7 +2970,7 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
header = data.mid(offset, sizeof(NVAR_VARIABLE_HEADER));
body = data.mid(offset + sizeof(NVAR_VARIABLE_HEADER), variableHeader->Size - sizeof(NVAR_VARIABLE_HEADER));
- UINT32 lastVariableFlag = pdata.emptyByte == 0 ? 0 : 0xFFFFFF;
+ UINT32 lastVariableFlag = pdata.emptyByte ? 0xFFFFFF : 0;
// Set default next to predefined last value
pdata.nvram.nvar.next = lastVariableFlag;
@@ -2977,7 +2985,7 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
// Add next node information to parsing data
if (variableHeader->Next != lastVariableFlag) {
subtype = Subtypes::LinkNvar;
- pdata.nvram.nvar.next = offset + variableHeader->Next;
+ pdata.nvram.nvar.next = variableHeader->Next;
}
// Variable with extended header
@@ -3046,7 +3054,7 @@ STATUS FfsParser::parseNvarStorage(const QByteArray & data, const QModelIndex &
for (int i = 0; i < model->rowCount(index); i++) {
nvarIndex = index.child(i, 0);
PARSING_DATA nvarPdata = parsingDataFromQModelIndex(nvarIndex);
- if (nvarPdata.nvram.nvar.next == offset) { // Previous link is present and valid
+ if (nvarPdata.nvram.nvar.next + nvarPdata.offset - parentOffset == offset) { // Previous link is present and valid
isInvalid = false;
break;
}
@@ -3102,8 +3110,14 @@ parsing_done:
QString info;
// Rename invalid variables according to their types
if (isInvalid) {
- name = QObject::tr("Invalid");
- subtype = Subtypes::InvalidNvar;
+ if (variableHeader->Next != lastVariableFlag) {
+ name = QObject::tr("Invalid link");
+ subtype = Subtypes::InvalidLinkNvar;
+ }
+ else {
+ name = QObject::tr("Invalid");
+ subtype = Subtypes::InvalidNvar;
+ }
}
else // Add GUID info for valid variables
info += QObject::tr("Variable GUID: %1\n").arg(name);
@@ -3122,7 +3136,7 @@ parsing_done:
pdata.nvram.nvar.attributes = variableHeader->Attributes;
// Add next node info
- if (variableHeader->Next != lastVariableFlag)
+ if (!isInvalid && variableHeader->Next != lastVariableFlag)
info += QObject::tr("\nNext node at offset: %1h").hexarg(parentOffset + offset + variableHeader->Next);
// Add extended header info
@@ -3165,6 +3179,14 @@ parsing_done:
msg(QObject::tr("parseNvarStorage: extended data size (%1h) is smaller than required for timestamp and hash (0x28)")
.hexarg(extendedData.size()), varIndex);
+ // Check variable name to be in the list of nesting variables
+ for (std::vector::const_iterator iter = nestingVariableNames.cbegin(); iter != nestingVariableNames.cend(); ++iter)
+ if (QString(*iter) == text.toLatin1()) {
+ STATUS result = parseNvarStorage(body, varIndex);
+ if (result)
+ msg(QObject::tr("parseNvarStorage: parsing of nested NVAR storage failed with error \"%1\"").arg(errorCodeToQString(result)), varIndex);
+ }
+
// Move to next variable
offset += variableHeader->Size;
}
diff --git a/common/nvram.cpp b/common/nvram.cpp
index 52cfb04..a98ae10 100644
--- a/common/nvram.cpp
+++ b/common/nvram.cpp
@@ -16,35 +16,32 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
QString variableAttributesToQstring(UINT8 attributes)
{
- QString str;
-
- if (attributes == 0x00 || attributes == 0xFF) {
+ if (attributes == 0x00 || attributes == 0xFF)
return QString();
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_RUNTIME) {
- str += QObject::tr(", Runtime");
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_ASCII_NAME) {
- str += QObject::tr(", AsciiName");
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_GUID) {
- str += QObject::tr(", Guid");
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_DATA_ONLY) {
- str += QObject::tr(", DataOnly");
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_EXT_HEADER) {
- str += QObject::tr(", ExtHeader");
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_HW_ERROR_RECORD) {
- str += QObject::tr(", HwErrorRecord");
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_AUTH_WRITE) {
- str += QObject::tr(", AuthWrite");
- }
- if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_VALID) {
- str += QObject::tr(", Valid");
- }
+
+ QString str;
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_RUNTIME)
+ str += QObject::tr(", Runtime");
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_ASCII_NAME)
+ str += QObject::tr(", AsciiName");
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_GUID)
+ str += QObject::tr(", Guid");
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_DATA_ONLY)
+ str += QObject::tr(", DataOnly");
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_EXT_HEADER)
+ str += QObject::tr(", ExtHeader");
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_HW_ERROR_RECORD)
+ str += QObject::tr(", HwErrorRecord");
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_AUTH_WRITE)
+ str += QObject::tr(", AuthWrite");
+ if (attributes & NVRAM_NVAR_VARIABLE_ATTRIB_VALID)
+ str += QObject::tr(", Valid");
+
return str.mid(2); // Remove the first comma and space
-}
\ No newline at end of file
+}
+
+std::vector nestingVariableNames = {
+ "StdDefaults",
+ "MfgDefaults"
+};
\ No newline at end of file
diff --git a/common/nvram.h b/common/nvram.h
index 9d85d65..80655c5 100644
--- a/common/nvram.h
+++ b/common/nvram.h
@@ -23,12 +23,18 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
// Let's start with NVAR storage, as the most difficult one
//
-//CEF5B9A3-476D-497F-9FDC-E98143E0422C
-const QByteArray NVRAM_NVAR_FILE_GUID
+// CEF5B9A3-476D-497F-9FDC-E98143E0422C
+const QByteArray NVRAM_NVAR_STORAGE_FILE_GUID
("\xA3\xB9\xF5\xCE\x6D\x47\x7F\x49\x9F\xDC\xE9\x81\x43\xE0\x42\x2C", 16);
+// 9221315B-30BB-46B5-813E-1B1BF4712BD3
+const QByteArray NVRAM_NVAR_EXTERNAL_DEFAULTS_FILE_GUID
+("\x5B\x31\x21\x92\xBB\x30\xB5\x46\x81\x3E\x1B\x1B\xF4\x71\x2B\xD3", 16);
+
extern QString variableAttributesToQstring(UINT8 attributes);
+extern std::vector nestingVariableNames;
+
// Make sure we use right packing rules
#pragma pack(push,1)
diff --git a/common/types.cpp b/common/types.cpp
index 31f367c..a541059 100644
--- a/common/types.cpp
+++ b/common/types.cpp
@@ -123,6 +123,8 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
case Types::NvramVariableNvar:
if (subtype == Subtypes::InvalidNvar)
return QObject::tr("Invalid");
+ if (subtype == Subtypes::InvalidLinkNvar)
+ return QObject::tr("Invalid link");
if (subtype == Subtypes::LinkNvar)
return QObject::tr("Link");
if (subtype == Subtypes::DataNvar)
diff --git a/common/types.h b/common/types.h
index 13c0242..1f59d0f 100644
--- a/common/types.h
+++ b/common/types.h
@@ -87,6 +87,7 @@ namespace Subtypes {
enum NvarVariableSubtypes {
InvalidNvar = 120,
+ InvalidLinkNvar,
LinkNvar,
DataNvar,
FullNvar